我已经研究了大多数可用的方法来找出一个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 机器、JVM 1.6_u26 64 位上运行的 Tomcat 实例,它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 内存中的一部分。VIRT bytop
和 Size by nmon
(两者应该代表相同)告诉我进程是 7530MB(或者确切地说是 7710952KB by nmon
)。这与预期的最大值相差太大:高于最大值 2009MB,并且根据 jmap 和 jstat 堆内存分配甚至没有达到峰值(2048-OldSpace + 1534-Eden_+_Survivors)。
top
还告诉我代码堆栈是 36KB(公平,对于初始 catalina 启动器),数据堆栈是 7.3GB(代表其余部分)。
这个 tomcat 服务器实例是唯一在这台机器上运行的实例,并且一直处于不稳定状态。需要每三天左右重新启动一次,因为机器有 7647544k RAM 可用,并且没有交换(出于性能原因)。我对限制进行了数学计算,并期望进程遵循它们,我发现为机器上运行的所有其他服务留出相当好的安全余量(除了 ssh 和 top 本身之外,没有一个应该打扰):7468 - 5521 = 1947。这对于“安全边际”来说几乎是太多了。
所以,我想了解所有这些内存从哪里使用,以及为什么不遵守限制。如果缺少任何信息,我很乐意提供。