Tomcat 内存消耗超过堆 + 烫发空间

2022-09-04 03:14:29

我观察到Tomcat RAM消耗在操作系统所说的和jVisualVM所说的不匹配。

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

从jVisualVM,Tomcat JVM正在使用

  • 最大堆数: 1,070,399,488 B
  • 堆大小: 298.438.656 B
  • 使用的堆:可变,介于 170MB 和 270MB 之间
  • 彼尔姆通用最大: 268,435,456 B
  • 烫发发电机容量: 248,872,960 B
  • PermGen使用:略有变化,约150MB

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

有谁知道我在这里错过了什么?

PS:我知道我的最大堆比使用的值高得多,但我认为如果JVM不使用它(即堆大小较低),这应该没有影响。

谢谢!马克


答案 1

根据我的理解,操作系统内存消耗应该是堆大小+ PermGen大小〜= 522 MB。但这比我观察到的少了471 MB。有谁知道我在这里错过了什么?

如果我理解这个问题,你所看到的是内存碎片和其他领域的JVM内存开销的组合。我们经常看到的生产程序的内存使用量是预期从内存设置中看到的2倍。

内存碎片可能意味着,尽管 JVM 认为操作系统已经给了它一些字节数,但由于内存子系统优化,必须给出一定的字节数。

在 JVM 开销方面,还有许多其他存储区域未包含在标准内存配置中。这是一个很好的讨论。引用:

以下是不属于垃圾回收堆但属于进程所需内存的事物的示例:

  • 实现 JVM 的代码
  • 用于实现 JVM 的数据结构的 C 手册堆
  • 系统中所有线程的堆栈(应用 + JVM)
  • 缓存的 Java 字节码(用于库和应用程序)
  • JITed 机器代码(用于库和应用程序)
  • 所有装入类的静态变量

答案 2

我们必须记住的第一件事是:,在这个“集合”中,permSpace通常是最大的块。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]

鉴于此,我想这里的关键是 JVM 选项 ,其中 n 从 0 到 100,它指定如果小于堆的堆是空闲的,则应扩展堆。默认情况下,它通常是40(Sun),因此当JVM分配内存时,它足以获得40%的可用空间(如果您有-Xms == -Xmx,则不适用)。它的“孪生选项”-XX:MaxHeapFreeRatio通常默认为70(星期日)。-XX:MinFreeHeapRatio=nn%

因此,在 Sun JVM 中,每个垃圾回收中活动对象的比例保持在 40-70% 以内。如果在 GC 之后,堆的空闲率不到 40%,则堆将展开。因此,假设您正在运行Sun JVM,我猜“java对象堆”的大小已达到约445Mb的峰值,从而产生约740 Mb的扩展“对象堆”(以保证40%的自由)。然后,(对象堆)+ (烫发空间)= 740 + 250 = 990 Mb。

也许您可以尝试输出 GC 详细信息或使用 jconsole 来验证堆大小的演变。

P.S.:在处理这样的问题时,最好发布操作系统和JVM的详细信息。