我观察到操作系统所说的内容与jVisualVM所说的内容之间的Tomcat RAM消耗不匹配。
从htop开始,Tomcat JVM的驻留内存 993 MB
从jVisualVM,Tomcat JVM正在使用
根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。但是,这比我观察的强471 MB 。
任何人都知道我在这里错过了什么?
PS:我知道我的最大堆远远高于使用的,但我认为如果JVM不使用它(即堆大小较低)应该没有效果。
谢谢! 马克
答案 0 :(得分:5)
根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。但这比我观察到的要少471 MB。任何人都知道我在这里缺少什么?
如果我理解你所看到的问题是memory fragmentation和其他领域的JVM内存开销的组合。我们经常看到生产程序的内存使用量是我们从内存设置中看到的2倍。
Memory fragmentation可能意味着虽然JVM认为操作系统已经给它一些字节数,但由于内存子系统的优化,必须给出一定的额外字节数。
就JVM开销而言,标准内存配置中还包含许多其他存储区域。这是一个good discussion about this。引用:
以下 是不属于垃圾收集堆的事物的示例 但它是该过程所需内存的一部分:
- 实施JVM的代码
- 实现JVM的数据结构的C手动堆
- 系统中所有线程的堆栈(app + JVM)
- 缓存的Java字节码(用于库和应用程序)
- JITed机器代码(用于库和应用程序)
- 所有已加载类的静态变量
答案 1 :(得分:4)
我们要记住的第一件事是:JVM process heap (OS process) = Java object heap + [Permanent space + Code generation + Socket buffers + Thread stacks + Direct memory space + JNI code + JNI allocated memory + Garbage collection]
,在这个“集合”中,permSpace通常是最大块。
考虑到这一点,我想这里的关键是JVM选项-XX:MinFreeHeapRatio=n
,其中n是0到100,它指定如果堆的小于n%
,则应该扩展堆。自由。默认情况下通常为40(Sun),因此当JVM分配内存时,它足以获得40%的空闲( 如果你有-Xms == -Xmx <这不适用/强>)。它的“双选项”,-XX:MaxHeapFreeRatio通常默认为70(太阳)。
因此,在Sun JVM中,每个垃圾收集中的活动对象的比例保持在40-70%之间。如果在GC之后少于40%的堆是空闲的,则扩展堆。因此,假设您正在运行Sun JVM,我猜测“java对象堆”的大小已达到约445Mb的峰值,因此产生了大约740 Mb的扩展“对象堆”(以保证40%免费) 。然后,(对象堆)+(perm空间)= 740 + 250 = 990 Mb。
也许您可以尝试输出GC详细信息或使用jconsole来验证堆大小的演变。
P.S。:在处理这样的问题时,最好发布操作系统和JVM细节。
答案 2 :(得分:3)
在应用程序启动期间,JVM将保留内存大小等于堆大小值(-Xmx)的大小,再加上其他内容的大小。这可以防止JVM以后返回操作系统以保留更多内存。
即使您的应用程序仅使用298mb的堆空间,仍然会为操作系统保留993mb。您需要阅读更多有关保留与已提交内存的信息。
在讨论垃圾收集时,您将阅读的大多数文章将从堆透视而不是操作系统级别引用分配。通过在启动时为应用程序保留内存,垃圾收集可以在自己的空间中工作。
如果您需要更多详细信息,请阅读文章Tuning Garbage Collection 以下是文件
中的一些重要内容初始化时,实际上保留了最大地址空间 除非需要,否则不会分配给物理内存。
另见文件
中的第3.2(iv)节在初始化虚拟机时,整个空间为 堆是保留的。保留的空间大小可以用 -Xmx选项。如果-Xms参数的值小于 -Xmx参数的值,而不是保留的所有空间 立即提交到虚拟机。
答案 3 :(得分:1)
操作系统将报告JVM使用的内存+程序使用的内存。因此它总是高于JVM报告的内存使用量。 JVM本身需要一定量的内存才能执行程序,操作系统无法区分。
不幸的是,使用系统内存工具并不是一种非常精确的跟踪程序内存消耗的方法。 JVM通常会分配大块内存,因此对象创建速度很快,但这并不意味着您的程序正在消耗该内存。
更好地了解程序实际执行的操作是运行jconsole并查看其中的内存使用情况。这是一个非常简单的工具,用于查看易于设置的内存。