JVM 进程与 JVM 堆内存使用情况

Posted

技术标签:

【中文标题】JVM 进程与 JVM 堆内存使用情况【英文标题】:JVM Process vs JVM Heap memory usage 【发布时间】:2011-10-10 18:35:53 【问题描述】:

我已经阅读了这个Process Memory Vs Heap -- JVM 我也有同样的问题。

jvm 进程的内存使用量一直在增加,并且从不缩小。我通过在 linux 服务器上做一个顶部检查。应用程序正在将作业调度到集群(使用 Quartz + Sun Java DRMAA API)

在应用程序生命周期中,java 堆空间保持在限制范围内,但 jvm 进程显示内存使用量稳步攀升,并且从未下降。

这是内存泄漏吗?如果是这样,为什么堆空间在限制范围内。谁能解释一下。

更新:当我通过 jconsole 跟踪时,我有 -Xmx1600m -Xms1600m 我可以看到堆空间在这个限制范围内,大约 450m,但顶部命令显示进程使用超过 900m。

【问题讨论】:

请提供更多详细信息...正在使用多少内存,它获得的最大内存是多少,经过多长时间,您正在使用什么 -X 和相关标志等。 你可以试试-XX:MaxHeapFreeRatio,看看能不能解决你的问题。 我正在研究类似的问题,top 显示 virt 大小超过 1GB,res 大小小于 50 MB。因此,virt/res 比率非常高。使用 jmap 或-XVerboseGCswitch 进行堆转储显示堆大小非常小(小于 50 MB)。如何找出占用非堆内存的内容?还有一些套接字 IO 涉及 usnig NIO,但我需要证据并且需要跟踪任何内存泄漏/查找根源。 【参考方案1】:

使用的总虚拟内存是最大堆 + 线程堆栈 + 直接内存 + perm gen + 共享库的总和。这永远不会缩小。

实际使用的主内存取决于占用了多少虚拟内存。共享库是共享的,因此拥有多个 JVM 不会导致内存翻倍等。

JVM 从不向操作系统释放内存,但是如果主内存长时间不使用,则可以根据需要将其换出。

【讨论】:

那么如果应用程序正在使用分配的1600M,为什么内核会用oom Killer杀死进程。我正在使用 centos,当我的 webapp 运行几个小时时,内核会杀死进程说 oom。同一个 java 进程的 jconsole 显示的价值远低于使用情况。我完全糊涂了。 操作系统不会触发 OOME 并且 OOME 不会杀死进程,尽管它可能会导致一个线程死亡并且应用程序无法运行。您需要查看 OOME,因为可能是另一个区域正在填充,例如 PermGen、直接内存或太多线程。也可能是您尝试分配一个大数组,该数组将失败(您不会在 jConsole 中看到任何内容,因为它只显示已用内存,而不是尝试) 我在系统日志信息中看到如下错误,这基本上杀死了java进程Jul 18 04:55:31 seqwd5 kernel: Out of memory: Killed process 16333, UID 501, (java). Jul 18 04:55:31 seqwd5 kernel: java invoked oom-killer: gfp_mask=0x201d2, order=0, oomkilladj=0 当您用完内存和交换时会发生此错误。我建议你增加你的交换空间,或者理想情况下你的主内存。您可以尝试减少使用的内存量,因为您似乎没有 1600M 可用。 只是一个评论,JVM能够将内存释放回操作系统。请参考Oracle的页面。 bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735【参考方案2】:

实际的内存消耗比你用 Xmx 等设置的多,这是正常的。 “java 会为其他事情分配内存,包括为每个线程分配一个堆栈。VM 的总内存消耗超过 -Xmx 的值并不罕见。”

【讨论】:

【参考方案3】:

参数 -Xmx1600m -Xms1600m 告诉 JVM 至少分配 1600MB 内存,最大分配 1600MB 内存。所以 JVM 应该在启动时分配 1600MB 并且永远不会释放它。

如果您希望 JVM 将内存释放回操作系统,那么 -Xms 应该尽可能低,并且您可能必须将 Java 1.7 与新的 G1 垃圾收集器一起使用。 stefankrause.net/wp/?p=14。

在 Mac OS X 10.8 和 Java 1.7 中使用 -Xms32m -Xmx256m -XX:+UseG1GC -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 在 System.gc() 运行后内存被释放回操作系统.

【讨论】:

这实际上是不正确的。这会导致 JVM 分配完整的 Xms 1.6GB,然后在第一个 GC 周期后释放几乎所有的 Xms(如果它没有被使用)。见java-monitor.com/forum/showthread.php?t=427 java-monitor.com/forum/showthread.php?t=427 【参考方案4】:

在堆中,Java 虚拟机 (JVM) 存储由 Java 应用程序创建的所有对象,例如通过使用“新”运算符。 Java 垃圾收集器 (gc) 可以在逻辑上将堆分成不同的区域,以便 gc 可以更快地识别可以被删除的对象

新对象的内存在运行时分配在堆上。实例变量存在于声明它们的对象中。

堆栈是存储方法调用和局部变量的地方。如果一个方法被调用,那么它的栈帧被放到调用栈的顶部。堆栈帧保存方法的状态,包括正在执行的代码行以及所有局部变量的值。堆栈顶部的方法始终是该堆栈的当前运行方法。线程有自己的调用栈。

如前所述,Java 对象是在堆中创建的。编程语言不提供让程序员决定是否应在堆栈中生成对象的可能性。但在某些情况下,最好在堆栈上分配一个对象,因为堆栈上的内存分配比堆中的内存分配便宜,堆栈上的释放是空闲的,并且堆栈由运行时有效地管理。

因此,JVM 使用内部转义分析来检查对象是否仅与线程或方法一起使用。如果 JVM 识别到这一点,它可能会决定在堆栈上创建对象,从而提高 Java 程序的性能。 (http://www.ibm.com/developerworks/java/library/j-nativememory-linux/)

【讨论】:

以上是关于JVM 进程与 JVM 堆内存使用情况的主要内容,如果未能解决你的问题,请参考以下文章

JVM:查看java内存情况命令

JVM与Linux内存关系分析

Linux与jvm内存关系分析

Linux与JVM的内存关系分析

JVM堆内存参数优化,让性能飞起来

Java进程内存泄漏判断及解决方法