Java进程内存远大于指定的限制

时间:2012-05-30 14:30:00

标签: java linux memory process

我已经研究了大多数可用的方法,以找出java进程实际使用的内存量。 到目前为止,我可以说我知道分配的总内存可能是以下一项或多项:

  • 堆内存(据说由我的-XX控制:MaxHeapSize = 4096m)
  • 永久记忆(据说由我-XX控制:MaxPermSize = 1024m)
  • 保留代码缓存(据说由我的-XX控制:ReservedCodeCacheSize = 256m)
  • 线程数N *线程大小(据说由我的-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方面,topnmon都告诉我这个过程分配的ResidentMemory是5.8GB - >大约5939,2MB。但我也知道这只是内存的一部分,即RAM内存的一部分。 VIRT top和大小nmon(两者都应该代表相同)告诉我这个过程是7530MB(或nmon精确到7710952KB)。 这与预期的最大值不同: 2009MB高于最大值,并且根据jmap和jstat,堆内存分配甚至没有达到峰值(2048-OldSpace + 1534-Eden _ + _ Survivors)。

top还告诉我代码堆栈是36KB(公平,对于初始的catalina启动器),数据堆栈是7.3GB(代表其余的)。

这个tomcat服务器实例是唯一一台在这台机器上运行的实例,并且一直存在一些不稳定性。需要每三天重启一次,因为机器有7647544k RAM可用,没有交换(出于性能原因)。我为限制做了数学运算,并期望按照它们的过程我看到它是一个非常好的安全边缘,留给机器上运行的所有其他服务(除了ssh和top本身之外没有任何一个应该打扰):7468 - 5521 = 1947.对于“安全边际”而言,这几乎是太多了。

所以,我想知道所使用的内存在哪里,为什么不遵守限制。如果缺少任何信息,我很乐意提供。

2 个答案:

答案 0 :(得分:5)

Plain and simple the JVM uses more memory than what is supplied in -Xms and -Xmx and the other command line parameters.

这是一个very detailed article on how the JVM allocates and manages memory,根据您在问题中的假设,它并不像您预期​​的那样简单,值得全面阅读。

许多实现中的ThreadStack大小具有最小限制,这些限制因操作系统而有时因JVM版本而异;如果将限制设置为低于JVM或OS的本机操作系统限制,则会忽略threadstack设置(有时必须设置ulix on * nix)。其他命令行选项以相同的方式工作,当提供的值太小时,默认默认为更高的值。不要假设传入的所有值都代表实际使用的值。

类加载器和Tomcat有不止一个,占用了大量内存,而这些内存很难被记录下来。 JIT占用了大量的内存,随着时间的推移交易空间,这在大多数情况下是一个很好的交易。

你引用的数字非常接近我的期望。

答案 1 :(得分:3)

虚拟内存是使用的地址空间量,我不会太担心你有64位应用程序。驻留者是实际使用的主存储器的数量。

您可以添加到列表中

  • 共享库,包括JVM。 ~0.5G
  • 直接内存(0到4G)默认情况下,最大值与堆最大值相同。
  • 内存映射文件。没有限制。

您可以执行pmap向您显示正在使用多少地址空间。

BTW:由于内存映射文件,我的进程显示640G VIRT在顶部。它可能比居民大小高很多。 ;)