当前位置:  开发笔记 > 编程语言 > 正文

Java 6过多的内存使用

如何解决《Java6过多的内存使用》经验,为你挑选了3个好方法。

Java 6是否比大预期的应用程序消耗更多的内存?

我有一个我已经开发多年的应用程序,直到现在我的特定测试配置大约需要30-40 MB; 现在使用Java 6u10和11,它在活动时需要几百个.它反弹很多,在50M到200M之间的任何地方,当它空转时,它会执行 GC并将内存放下.此外,它还会产生数百万的页面错误.所有这些都是通过Windows任务管理器观察到的.

因此,我在我的探查器(jProfiler)下运行它并使用jVisualVM,它们都指示通常适度的堆和大约30M的用户使用,即使完全处于我的负载测试周期.

所以我很神秘!它不只是从Windows虚拟内存池中请求更多内存 - 这显示为200M"内存使用".

澄清:我希望对此非常清楚 - 使用Java VisualVM在18小时内观察到类堆和perm gen堆已经完全稳定.分配的易失性堆(eden和tenured)不动以16MB(它在最初的几分钟内到达),并且这个内存的使用波动在一个完美的模式,从8MB到16MB均匀增长,此时GC启动将它降回8MB.在这18小时的时间内,系统在进行压力测试后处于恒定的最大负载下.在许多运行中都可以看到这种行为完美一致的可重复性.唯一的异常现象是,虽然这是通过任务管理器观察到的从Windows获取的内存,但从64MB到900 + MB的所有地方都会出现波动.

更新2008-12-18:我用-Xms16M -Xmx16M运行程序没有任何明显的不利影响 - 性能很好,总运行时间大致相同.但是短时间内的内存使用量仍然达到了180M左右.

更新2009-01-21:似乎答案可能是线程数 - 请参阅下面的答案.


编辑:我的意思是数百万页错误 - 在30M +区域.

编辑:我有一台4G机器,所以200M在这方面并不重要.



1> Michael Borg..:

在对Ran的回答的评论中的讨论中,这是一个测试用例,证明JVM 在某些情况下会将内存释放回操作系统:

public class FreeTest
{
    public static void main(String[] args) throws Exception
    {
        byte[][] blob = new byte[60][1024*1024];
        for(int i=0; i

在Java 1.4和Java 6 JVM(来自Sun)上,当计数达到40左右时,我看到JVM进程的大小减小了.

您甚至可以使用-XX调整确切行为:MaxHeapFreeRatio和-XX:MinHeapFreeRatio选项 - 该页面上的某些选项也可以帮助回答原始问题.



2> Ran Biron..:

我不知道页面错误.但是关于为Java分配的巨大内存:

    Sun的JVM 只分配内存,从不释放它(直到JVM死亡)只有在内部内存需求和分配的内存之间的特定比率下降到(可调)值之后才释放内存.JVM以-Xms中指定的数量开始,可以扩展到-Xmx中指定的数量.我不确定默认值是什么.每当JVM需要更多内存(新对象/基元/数组)时,它就会从操作系统中分配整个块.然而,当需求消退时(暂时需要,也见2),它不会立即将内存释放回操作系统,而是在达到该比率之前保持自身.我曾经被告知JRockit表现得更好,但我无法验证它.

    Sun的JVM基于多个触发器运行完整的GC.其中一个是可用内存量 - 当它下降太多时,JVM会尝试执行完整的GC以释放更多内存.因此,当从OS分配更多内存(瞬间需要)时,降低了完整GC的可能性.这意味着虽然您可能会看到30Mb的"实时"对象,但可能会有更多"死"对象(无法访问),只是等待GC发生.我知道你的套件有一个很棒的视图叫做"死对象",你可以看到这些"遗留物".

    在"-server"模式下,Sun的JVM以并行模式运行GC(而不是旧的串行"停止世界"GC).这意味着虽然可能会收集垃圾,但由于其他线程占用了所有可用的CPU时间,因此可能无法立即收集垃圾.它将在到达内存之前收集(好吧,有点.请参阅http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html),如果可以从操作系统分配更多内存,它可能会在GC运行之前.

结合起来,一个大的初始内存配置和创建大量短期对象的短突发可能会创建一个所描述的场景.

编辑:将"never deallcoates"更改为"仅在达到比率后".



3> Michael Borg..:

过多的线程创建完美地解释了您的问题:

每个线程都有自己的堆栈,它与堆内存分开,因此不会被分析器注册

默认的线程堆栈大小非常大,IIRC 256KB(至少是Java 1.3)

Tread堆栈内存可能不会被重用,因此如果您创建并销毁大量线程,则会出现大量页面错误

如果您确实需要拥有数百个线程,则可以通过-Xss命令行参数配置线程堆栈大小.

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有