【发布时间】:2012-06-04 19:27:03
【问题描述】:
我已经研究了大多数可用的方法来找出一个 java 进程真正使用了多少内存。 到目前为止,我可以说我知道分配的总内存可能是以下一项或多项:
- 堆内存(应该由我的 -XX:MaxHeapSize=4096m 控制)
- 永久内存(据说由我的 -XX:MaxPermSize=1024m 控制)
- 保留代码缓存(应该由我的 -XX:ReservedCodeCacheSize=256m 控制)
- N of Threads * Thread Size(假设由我的 -XX:ThreadStackSize=1024 控制)
但结果与 linux 告诉我的相差太大,我发现任何方法都可用于获取 java 进程的内存消耗。
在我的例子中,它是一个运行在 Ubuntu 11.10 x86_64 机器上的 Tomcat 实例,JVM 1.6_u26 64 位,ps -ALcf | grep org.apache.catalina.startup.Bootstrap | wc -l 告诉我我有 145 个线程或进程正在运行,它们都链接到同一个根进程 (Tomcat) .
所有的总结应该给我总的最大记忆
(4096MB) + (1024MB) + (256MB) + 145 * (1024KB) = 5521MB。
jmap -heap PID 告诉我的,ManagementFactory.memoryMXBean.(heapMemoryUsage + nonHeapMemoryUsage).getCommitted() 告诉我的,上面的理论值都是对的。
现在到 linux 端,top 和 nmon 都告诉我这个进程分配的 ResidentMemory 是 5.8GB -> 大约 5939,2MB。但我也知道这只是内存的一部分,是实时 RAM 内存中的一部分。 top 的 VIRT 和 nmon 的 Size(两者应该代表相同)告诉我该进程是 7530MB(或 nmon 准确地说是 7710952KB)。
这与预期的最大值相差太大:比最大值高出 2009MB,根据 jmap 和 jstat,堆内存分配甚至没有达到峰值(2048-OldSpace + 1534-Eden__Survivors)。
top 还告诉我代码堆栈是 36KB(公平,对于初始 catalina 启动器),数据堆栈是 7.3GB(代表其余部分)。
这个 tomcat 服务器实例是这台机器上唯一运行的一个,并且已经看到一些不稳定。需要每三天左右重新启动一次,因为机器有 7647544k RAM 可用,并且没有交换(出于性能原因)。我对限制进行了数学计算,并期望进程遵循它们,我发现为机器上运行的所有其他服务留出相当好的安全余量(除了 ssh 和 top 本身之外,没有一个应该打扰):7468 - 5521 = 1947。这对于“安全边际”来说几乎是太多了。
所以,我想了解所有这些内存从哪里使用,以及为什么不遵守限制。如果缺少任何信息,我很乐意提供。
【问题讨论】:
-
在顶部的细分中,您忘记提到 JNI 在堆外分配内存。您正在分析的应用程序是否可能正在使用 JNI?
-
我不知道是否有办法确定(有吗?),但我认为这不是我对整个应用程序的了解。至少我可以保证没有明确使用它。应用程序连接到外部数据库(不在同一台机器上),不知道是否可以直接使用 JNI。无论如何,整个池的缓存在另一边,在数据库端,所以不应该算在内。
-
RSS 与 Java 堆不同。 VIRT 包含映射文件