【问题标题】:Sun JVM Committed Virtual Memory High ConsumptionSun JVM 承诺虚拟内存高消耗
【发布时间】:2011-03-26 06:04:09
【问题描述】:

我们有生产 Tomcat (6.0.18) 服务器,它使用以下设置运行:

-server -Xms7000M -Xmx7000M -Xss128k -XX:+UseFastAccessorMethods 
-XX:+HeapDumpOnOutOfMemoryError -Dcom.sun.management.jmxremote.port=7009 
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false -verbose:gc -XX:+PrintGCDetails 
-XX:+PrintGCTimeStamps 
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=/opt/apache-tomcat-6.0.18/conf/logging.properties 
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n 
-Djava.endorsed.dirs=/opt/apache-tomcat-6.0.18/endorsed 
-classpath :/opt/apache-tomcat-6.0.18/bin/bootstrap.jar

java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) 64-Bit Server VM (build 11.2-b01, mixed mode)

经过一段时间的工作,我们得到(通过 JConsole)以下内存消耗:

Current heap size: 3 034 233 kbytes
Maximum heap size: 6 504 832 kbytes
Committed memory:  6 504 832 kbytes
Pending finalization: 0 objects
Garbage collector: Name = 'PS MarkSweep', Collections = 128, Total time spent = 16 minutes
Garbage collector: Name = 'PS Scavenge', Collections = 1 791, Total time spent = 17 minutes

Operating System: Linux 2.6.26-2-amd64
Architecture: amd64
Number of processors: 2

Committed virtual memory: 9 148 856 kbytes
Total physical memory:  8 199 684 kbytes
Free physical memory:     48 060 kbytes
Total swap space: 19 800 072 kbytes
Free swap space: 15 910 212 kbytes

问题是为什么我们有很多已提交的虚拟内存?请注意,最大堆大小约为 7Gb(正如预期的那样,因为 Xmx=7G)。

顶部显示如下:

31413 root  18  -2 8970m 7.1g  39m S   90 90.3 351:17.87 java

为什么 JVM 需要额外的 2Gb!虚拟内存?我可以像在 JRockit http://blogs.oracle.com/jrockit/2009/02/why_is_my_jvm_process_larger_t.html 中那样获得非堆内存分配吗?

编辑 1:Perm 为 36M。

【问题讨论】:

    标签: java memory jvm


    【解决方案1】:

    您可能想尝试将 JConsole 连接到您的 JVM 并查看内存分配...也许您的 Perm 空间占用了这额外的 2GB...堆只是您的 VM 需要保持活力的一部分...

    【讨论】:

    • 没那么简单。烫发是36M。 JConsole 一直附加))。
    • 我绝对没有说这很简单 :P 该应用程序是否已经运行了很长时间?也许有泄漏?
    • 是的,要达到这个状态需要几个小时的工作。但是,它似乎很稳定(除了整台机器过载)。你的意思是什么类型的泄漏?一些原生库?
    • 原生库,VM中的bug...这种事情发生了。
    • 是的,这可能是问题所在。除了一一关闭应用程序的块外,您是否知道是否有任何工具可以确定此类泄漏?看来 JRockit 的 print_memusage 模拟会很有帮助......
    【解决方案2】:

    似乎这个问题是由 JVM 的大量页面错误引起的。最有可能的是,当 Sun 的 JVM 遇到大量页面错误时,它会开始分配额外的虚拟内存(仍然不知道为什么),这反过来可能会进一步增加 IO 压力等等。结果,我们得到了非常高的虚拟内存消耗和完全 GC 的周期性挂起(长达 30 分钟)。

    三件事帮助我们在生产中获得稳定的工作:

    1. Linux 内核交换趋势的降低(有关描述,请参见此处What Is the Linux Kernel Parameter vm.swappiness?)有很大帮助。我们在所有运行繁重后台 JVM 任务的 Linux 服务器上都有vm.swappiness=20

    2. 减小最大堆大小值 (-Xmx) 以防止对操作系统本身造成过大压力。我们现在在 12GB 的机器上有 9GB 的价值。

    3. 最后但非常重要 - 代码分析和内存分配瓶颈优化,以尽可能消除分配突发。

    就是这样。现在服务器运行良好。

    【讨论】:

    • 这似乎不是您问题的答案...您的问题是:“问题是为什么我们有很多已提交的虚拟内存?”我看到类似的堆大小低~200M,但JDK虚拟大小很大~1.7G。知道 JVM 在哪里泄漏了这些内存,或者如何诊断泄漏,仍然很有用......
    • 并继续增长?据我了解,JVM 使用一些额外的内存用于线程堆栈(BTW 是否使用了很多线程?)、库、控制结构等是很正常的......
    • 不,1.7G 似乎是一个稳定的状态。我们在这里使用 Eclipse 的所有 VM 上都看到了这一点。 jconsole 输出没有显示任何 VM 内部内存(代码缓存、堆栈等)超过 100M 和所有其他指标:线程数、CPU 使用率、permgen + 堆,似乎都在合理的范围内。抓住根本原因的稻草......
    【解决方案3】:

    -Xms7000M -Xmx7000M

    这对我来说是对 JVM “分配 7gb 作为初始堆大小,最大为 7gb”。

    因此,对于操作系统而言,进程将始终为 7gb,因为这是 JVM 通过 Xms 标志所要求的。 它实际上在 JVM 内部使用的是被报告为几百 mb 的堆大小。通常,当您防止由于过多的垃圾收集而导致减速时,您会设置一个较高的 Xms。当 JVM 达到(JVM 定义的)正在使用的内存百分比时,它会进行快速垃圾收集。如果这无法释放内存,那么它将尝试详细收集。最后,如果这失败并且 Xmx 定义的最大内存还没有达到,那么它会要求操作系统提供更多内存。所有这些都需要时间,并且可以在生产服务器上真正注意到 - 提前这样做可以避免这种情况发生。

    【讨论】:

      【解决方案4】:

      我不熟悉 jconsole,但你确定 JVM 正在使用额外的 2Gb 吗?在我看来,是操作系统或其他进程使总容量达到 9Gb。

      此外,对于 JVM 使用比 -Xmx 参数允许的更多的虚拟内存的常见解释是,您有内存映射文件 (MappedByteBuffer) 或使用使用 MappedByteBuffer 的库。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-05-18
        • 1970-01-01
        • 2012-12-09
        • 1970-01-01
        • 2011-12-18
        • 2014-04-23
        • 2021-03-29
        相关资源
        最近更新 更多