Java Tomcat的内存消耗比heap+;永磁空间

Java Tomcat的内存消耗比heap+;永磁空间,java,tomcat,memory,jvm,Java,Tomcat,Memory,Jvm,我观察到操作系统所说的和jVisualVM所说的之间Tomcat RAM消耗不匹配 从htop来看,Tomcat JVM的驻留内存993 MB 从jVisualVM,Tomcat JVM正在使用 堆最大值:1070399488 B 堆大小:298.438.656 B 使用的堆:变量,介于170MB和270MB之间 PermGen最大值:268435456 B 永久性大小:248872960 B 使用的PermGen:略有变化,约150MB 据我所知,操作系统的内存消耗应该是堆大小+永久大小~

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

从htop来看,Tomcat JVM的驻留内存993 MB

从jVisualVM,Tomcat JVM正在使用

  • 堆最大值:1070399488 B
  • 堆大小:298.438.656 B
  • 使用的堆:变量,介于170MB和270MB之间
  • PermGen最大值:268435456 B
  • 永久性大小:248872960 B
  • 使用的PermGen:略有变化,约150MB
据我所知,操作系统的内存消耗应该是堆大小+永久大小~=522MB。但这比我观察到的要少471MB

有人知道我错过了什么吗

PS:我知道我的最大堆比使用的要高得多,但我假设如果JVM不使用它(即堆大小较低),这应该没有任何影响

谢谢!
Marc

在应用程序启动期间,JVM将保留大约等于堆最大值(-Xmx)大小的内存,再加上一点用于其他内容的内存。这可以防止JVM以后必须返回操作系统以保留更多内存

即使您的应用程序仅使用298mb的堆空间,操作系统仍会保留993mb的堆空间。您需要在保留内存和提交内存中读取更多内容

在讨论垃圾收集时,您将阅读的大多数文章都是从堆的角度而不是从操作系统级别来讨论分配的。通过在启动时为应用程序保留内存,垃圾收集可以在自己的空间中工作

如果您需要更多详细信息,请阅读本文 以下是这份文件中的一些重要作用

初始化时,实际上保留了最大地址空间,但 除非需要,否则不分配给物理内存

另请参阅本文件第3.2(iv)节

在虚拟机初始化时,虚拟机的整个空间 堆是保留的。保留空间的大小可以使用指定 -Xmx选项。如果-Xms参数的值小于 -Xmx参数的值,而不是保留的所有空间 立即提交到虚拟机

据我所知,操作系统的内存消耗应该是堆大小+永久大小~=522MB。但这比我观察到的少471MB。有人知道我错过了什么吗

如果我理解这个问题,那么您看到的是其他方面的内存开销和JVM内存开销的结合。我们经常看到生产程序的内存使用量是内存设置的2倍

这可能意味着,尽管JVM认为操作系统给了它一定数量的字节,但由于内存子系统的优化,必须增加一定数量的字节

就JVM开销而言,标准内存配置中不包括许多其他存储区域。这是一个例子。引述:

以下 是不属于垃圾收集堆的事物的示例 但它们是过程所需内存的一部分:

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

操作系统将报告JVM使用的内存+程序使用的内存。因此,它将始终高于JVM报告的内存使用率。JVM本身需要一定数量的内存才能执行您的程序,而操作系统无法区分这两者之间的区别

不幸的是,使用系统内存工具并不是跟踪程序内存消耗的非常精确的方法。JVM通常会分配大量内存,以便快速创建对象,但这并不意味着您的程序正在消耗这些内存


了解程序实际在做什么的更好方法是运行jconsole并查看那里的内存使用情况。这是一个非常简单的工具,用于查看易于设置的内存。

我们必须记住的第一件事是:
JVM进程堆(OS进程)=Java对象堆+[永久空间+代码生成+套接字缓冲区+线程堆栈+直接内存空间+JNI代码+JNI分配内存+垃圾收集]
,在这个“集合”中,permSpace通常是最大的块

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

因此,在太阳JVM中,每次垃圾收集时的活动对象比率保持在40-70%之间。如果GC后堆的可用空间不足40%,则堆将被扩展。因此,假设您正在运行Sun JVM,我猜“java对象堆”的大小已经达到了大约445Mb的峰值,从而产生了大约740MB的扩展“对象堆”(以保证40%的空闲)。然后,(对象堆)+(perm空间)=740+250=990MB

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


注意:在处理此类问题时,最好发布操作系统和JVM的详细信息。

堆号是否同时包括老代和年轻代?在您的帖子中,您有两次提到“PermGem大小”:“PermGen大小:248872960 B,PermGen大小:略有变化,大约为1