是否值得减轻垃圾收集的影响?

时间:2009-08-05 10:41:52

标签: java memory-management caching java-me garbage-collection

我有一个应用程序,内存配置文件看起来像这样:

Jaggy
(来源:kupio.com

内存使用的缓慢向上爬行是由批次和大量小而简单的瞬态对象的分配引起的。在内存不足的情况下(这是一个移动应用程序),与较少限制的内存量相比,GC开销很明显。

由于我们知道,由于应用程序的性质,这些峰值将继续存在,我正在考虑某种众多的瞬态对象池(真棒名称)。这些对象将在应用程序的生命周期中存在,并在可能的情况下重复使用(对象的生命周期很短且可预测性很强)。

希望通过减少收集的对象数量并提高性能来减轻GC的影响。

显然,这也有自己的性能限制,因为“分配”会更昂贵,并且维护缓存本身会有开销。

由于这将是对大量代码的相当大的侵入性更改,我想知道是否有人尝试了类似的东西,如果它是一个好处,或者是否有任何其他已知的方法来缓解GC有点情况。有关管理可重用对象缓存的有效方法的想法也是受欢迎的。

8 个答案:

答案 0 :(得分:6)

这类似于GoF模式书中详述的flyweight模式(请参阅下面的编辑)。由于在减少对象创建,同步和GC开销方面取得了进展,对象池在“普通”虚拟机中已失宠。然而,这些肯定已经存在了很长时间,试着看看它们是否有帮助当然没问题!

当然,与上面提到的池化开销相比,对象池仍然用于具有非常昂贵的创建开销的对象(数据库连接是一个明显的例子)。

只有测试会告诉您汇集方法是否适用于您的目标平台!

编辑 - 我将OP “尽可能重新使用”表示对象是不可变的。当然情况可能并非如此,flyweight模式实际上是关于共享的不可变对象(Enum是flyweight的一个例子)。可变(read:unshareable)对象不是flyweight模式的候选对象,但是(当然)对象池。

答案 1 :(得分:2)

通常情况下,我会说这是调整VM的GC参数的工作,减少了尖端,但对于不是真正的选项的移动应用程序。因此,如果您使用的JVms无法修改其GC行为,那么老式的对象池可能是最佳解决方案。

Apache Commons Pool库对此有好处,但如果这是一个移动应用程序,那么您可能不需要库依赖开销。

答案 2 :(得分:2)

实际上,这个图对我来说看起来很健康。 GC正在回收大量对象,然后内存返回到相同的基本级别。根据经验,这意味着GC正在有效地工作。

对象池的问题在于它会使您的应用程序变得更慢,更复杂并且可能更加错误。更重要的是,它实际上可以使每个GC运行更长时间。 (池中的所有“空闲”对象都是非垃圾,需要由GC标记等。)

答案 3 :(得分:2)

J2ME是否有分代垃圾收集器?如果是这样,它可以做许多小巧,快速的收藏,从而减少暂停。您可以尝试减少eden内存空间(小内存空间)以增加频率并减少集合的延迟,从而减少暂停。

虽然,想到它,我的猜测是你无法调整gc行为,因为一切都可能在同一个VM中运行(这里只是一个猜测)。

答案 4 :(得分:1)

您可以查看this link描述Concurrent Mark Sweep收集器的增强功能,但我不确定它是否可用于J2ME。特别要注意:

“并发标记扫描收集器,也称为并发收集器或CMS,针对对垃圾收集暂停敏感的应用程序。”

...“在JDK 6中,CMS收集器可以选择性地同时执行这些收集,以避免响应System.gc()或Runtime.getRuntime()。gc()调用的长时间暂停。要启用此功能功能,添加选项“

-XX:+ExplicitGCInvokesConcurrent 

答案 5 :(得分:1)

结帐this link。特别是:

  

列举一些问题   对象池创建:首先,未使用   对象占用内存空间为no   原因; GC必须处理未使用的   对象也是如此,将其扣留在上面   没用的无用物品;并在   为了从中获取对象   对象池是一个同步   通常需要哪个慢得多   比异步分配   本地可用。

答案 6 :(得分:0)

您正在讨论可重用对象实例池。

class MyObjectPool { 
    List<MyObject> free= new LinkedList<MyObject>();
    List<MyObject> inuse= new LinkedList<MyObject>();
    public MyObjectPool(int poolsize) {
        for( int i= 0; i != poolsize; ++i ) {
           MyObject obj= new MyObject();
           free.add( obj );
        }
    }
    pubic makeNewObject( ) {
        if( free.size() == 0 ) {
            MyObject obj= new MyObject();
            free.add( obj );
        }
        MyObject next= free.remove(0);
        inuse.add( next );
        return next;
   }
   public freeObject( MyObject obj ) {
       inuse.remove( obj );
       free.add( obj );
   }
}
        return in

答案 7 :(得分:0)

鉴于this回答表明在J2ME中调整垃圾收集本身的空间不大,那么如果GC是一个问题,唯一的另一个选择是查看如何更改应用程序以提高性能/内存用法。也许所引用答案中的一些建议适用于您的申请。

正如oxbow_lakes所说,你的建议是标准的设计模式。但是,与任何优化一样,真正了解它将改进您的特定应用程序的唯一方法是实现和分析。