简体   繁体   English

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

[英]Tomcat memory consumption is more than heap + permgen space

I am observing a mismatch in Tomcat RAM consumption between what the OS says and what jVisualVM says. 我观察到操作系统所说的内容与jVisualVM所说的内容之间的Tomcat RAM消耗不匹配。

From htop, the Tomcat JVM is has 993 MB of resident memory 从htop开始,Tomcat JVM拥有993 MB的驻留内存

From jVisualVM, the Tomcat JVM is using 从jVisualVM,Tomcat JVM正在使用

  • Heap Max: 1,070,399,488 B 堆最大值:1,070,399,488 B
  • Heap Size: 298.438.656 B 堆大小: 298.438.656 B.
  • Heap Used: variable, between 170MB and and 270MB 堆使用:可变,介于170MB和270MB之间
  • PermGen Max: 268,435,456 B PermGen Max:268,435,456 B
  • PermGen Size: 248,872,960 B PermGen尺寸: 248,872,960 B
  • PermGen Used: slightly variable, around 150MB PermGen使用:略有变化,约150MB

From my understanding the OS memory consumption should be Heap Size + PermGen Size ~= 522 MB. 根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。 But that's 471 MB less than what I'm observing. 但这比我观察到的要少471 MB

Anyone got an idea what am I missing here? 任何人都知道我在这里错过了什么?

PS: I know that my max heap is much higher than what is used, but I'm assuming that should have no effect if the JVM does not use it (ie Heap Size is lower). PS:我知道我的最大堆远远高于使用的,但我认为如果JVM不使用它(即堆大小较低)应该没有效果。

Thanks! 谢谢! Marc

From my understanding the OS memory consumption should be Heap Size + PermGen Size ~= 522 MB. 根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。 But that's 471 MB less than what I'm observing. 但这比我观察到的要少471 MB。 Anyone got an idea what am I missing here? 任何人都知道我在这里错过了什么?

If I understand the question what you are seeing is a combination of memory fragmentation and JVM memory overhead in other areas. 如果我理解你所看到的问题是内存碎片和其他领域的JVM内存开销的组合。 We often see 2 times the memory usage for our production programs than we would expect to see from our memory settings. 我们经常看到生产程序的内存使用量是我们从内存设置中看到的2倍。

Memory fragmentation can mean that although the JVM thinks that the OS has given it some number of bytes, there is a certain addition number of bytes that had to be given because of memory subsystem optimizations. 内存碎片可能意味着虽然JVM认为操作系统已经给它提供了一定数量的字节,但由于内存子系统的优化,必须给出一定的额外字节数。

In terms of JVM overhead, there are a number of other storage areas that are not included in the standard memory configs. 就JVM开销而言,标准内存配置中还包含许多其他存储区域。 Here's a good discussion about this . 这是一个很好的讨论 To quote: 报价:

The following are examples of things that are not part of the garbage collected heap and yet are part of the memory required by the process: 以下是不属于垃圾收集堆的事物的示例,但它们是进程所需的内存的一部分:

  • Code to implement the JVM 用于实现JVM的代码
  • The C manual heap for data structures implementing the JVM 实现JVM的数据结构的C手动堆
  • Stacks for all of the threads in the system (app + JVM) 系统中所有线程的堆栈(app + JVM)
  • Cached Java bytecode (for libraries and the application) 缓存的Java字节码(用于库和应用程序)
  • JITed machine code (for libraries and the application) JITed机器代码(用于库和应用程序)
  • Static variables of all loaded classes 所有已加载类的静态变量

The first thing we have to bear in mind is that: 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] , where in this "collection" permSpace is usually the bigest chunk. 我们要记住的第一件事是: 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通常是最大块。

Given that, I guess the key here is the JVM option -XX:MinFreeHeapRatio=n , where n is from 0 to 100, and it specifies that the heap should be expanded if less than n% of the heap is free. 鉴于此,我想这里的关键是JVM选项-XX:MinFreeHeapRatio=n ,其中n是0到100,并且它指定如果堆的剩余空间少于n% ,则应该扩展堆。 It is usually 40 by default (Sun), so when the JVM allocates memory, it gets enough to get 40% free ( this is not applicable if you have -Xms == -Xmx ). 默认情况下它通常为40(Sun),因此当JVM分配内存时,它足以获得40%的空闲( 如果你有-Xms == -Xmx则不适用 )。 Its "twin option", -XX:MaxHeapFreeRatio usually defaults to 70 (Sun). 它的“双选项”,-XX:MaxHeapFreeRatio通常默认为70(太阳)。

Therefore, in a Sun JVM the ratio of living objects at each garbage collection is kept within 40-70%. 因此,在Sun JVM中,每个垃圾收集中的活动对象的比率保持在40-70%之间。 If less than 40% of the heap is free after a GC, then the heap is expanded. 如果在GC之后少于40%的堆是空闲的,则扩展堆。 So assuming you are running a Sun JVM, I would guess that the size of the "java object heap" has reached a peak of about 445Mb, thus producing an expanded "object heap" of about 740 Mb (to guarantee a 40% free). 因此,假设您正在运行Sun JVM,我猜测“java对象堆”的大小已达到约445Mb的峰值,因此产生了大约740 Mb的扩展“对象堆”(以保证40%免费) 。 Then, (object heap) + (perm space) = 740 + 250 = 990 Mb. 然后,(对象堆)+(perm空间)= 740 + 250 = 990 Mb。

Maybe you can try to output GC details or use jconsole to verify the evolution of the heap size. 也许您可以尝试输出GC详细信息或使用jconsole来验证堆大小的演变。

PS: when dealing with issues like this, it is good to post OS and JVM details. PS:在处理这样的问题时,最好发布操作系统和JVM细节。

During the startup of your application the JVM will reserve memory equal to roughly the size of your Heap Max value (-Xmx) plus a bit more for other stuff. 在应用程序启动期间,JVM将保留大致等于堆大小值(-Xmx)的内存以及其他内容的内存。 This prevents the JVM from having to go back to the OS to reserve more memory later. 这可以防止JVM以后返回操作系统以保留更多内存。

Even if your application is only using 298mb of heap space, there will still be the 993mb reserved with the OS. 即使您的应用程序仅使用298mb的堆空间,仍然会为操作系统保留993mb。 You will need to read more into reserved vs committed memory. 您需要阅读更多有关保留与已提交内存的内容。

Most of the articles you will read when talking about garbage collection will refer to allocation from a heap perspective and not the OS level. 在讨论垃圾收集时,您将阅读的大多数文章将从堆透视而不是操作系统级别引用分配。 By reserving the memory at start-up for your application, the garbage collection can work in its own space. 通过在启动时为应用程序保留内存,垃圾收集可以在自己的空间中工作。

If you need more details, read the article Tuning Garbage Collection Here are some important exerts from the document 如果您需要更多详细信息,请阅读文章Tuning Garbage Collection以下是文档中的一些重要内容

At initialization, a maximum address space is virtually reserved but not allocated to physical memory unless it is needed. 在初始化时,除非需要,否则实际上保留了最大地址空间但未分配给物理内存。

Also look at section 3.2 (iv) in the document 另请参阅文件中的第3.2(iv)节

At initialization of the virtual machine, the entire space for the heap is reserved. 在初始化虚拟机时,将保留堆的整个空间。 The size of the space reserved can be specified with the -Xmx option. 可以使用-Xmx选项指定保留空间的大小。 If the value of the -Xms parameter is smaller than the value of the -Xmx parameter, not all of the space that is reserved is immediately committed to the virtual machine. 如果-Xms参数的值小于-Xmx参数的值,则不会立即将所有保留的空间提交给​​虚拟机。

The OS will report the memory used by the JVM + the memory used by your program. 操作系统将报告JVM使用的内存+程序使用的内存。 So it will always be higher than what the JVM reports as memory usage. 因此它总是高于JVM报告的内存使用量。 There is a certain amount of memory need by the JVM itself in order execute your program and the OS can't tell the difference. JVM本身需要一定量的内存才能执行程序,操作系统无法区分。

Unfortunately using the system memory tools isn't a very precise way to track your programs memory consumption. 不幸的是,使用系统内存工具并不是一种非常精确的跟踪程序内存消耗的方法。 JVM's typically allocate large blocks of memory so object creation is quick, but it doesn't mean your program is consuming that memory. JVM通常会分配大块内存,因此对象创建很快,但这并不意味着您的程序正在消耗该内存。

A better way of knowing what your program is actually doing is to run jconsole and look at the memory usage there. 了解程序实际执行的更好方法是运行jconsole并查看其中的内存使用情况。 That's a very simple tool for looking at memory that's easy to set up. 这是一个非常简单的工具,用于查看易于设置的内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM