Tomcat内存消耗超过堆+ permgen空间

时间:2011-11-07 14:35:56

标签: java tomcat memory jvm

我观察到操作系统所说的内容与jVisualVM所说的内容之间的Tomcat RAM消耗不匹配。

从htop开始,Tomcat JVM的驻留内存 993 MB

从jVisualVM,Tomcat JVM正在使用

  • 堆最大值:1,070,399,488 B
  • 堆大小: 298.438.656 B
  • 使用堆:变量,介于170MB和270MB之间
  • PermGen Max:268,435,456 B
  • PermGen尺寸: 248,872,960 B
  • PermGen使用:略有变化,约150MB

根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。但是,这比我观察的强471 MB

任何人都知道我在这里错过了什么?

PS:我知道我的最大堆远远高于使用的,但我认为如果JVM不使用它(即堆大小较低)应该没有效果。

谢谢! 马克

4 个答案:

答案 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并查看其中的内存使用情况。这是一个非常简单的工具,用于查看易于设置的内存。