2009-08-05 34 views
11

我有一个应用程序,内存配置文件看起来是这样的:值得减轻垃圾回收的影响吗?

Jaggy http://kupio.com/image-dump/spikeymem.png

内存使用量的缓慢向上爬行是由许许多多小,操作简单,临时对象的分配造成的。在内存不足的情况下(这是一款移动应用程序),与较少限制的内存量相比,GC开销显而易见。

由于我们知道,由于应用程序的性质,这些尖峰将持续到来,我正在考虑某种形式的众多临时对象(真棒名称)。这些对象将在应用程序的整个生命周期中生存并在可能的情况下被重新使用(对象的生命周期很短且可预测性很高)。

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

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

由于这将是一个相当大和侵入性的变化到大量的代码,我想知道是否有人尝试过类似的东西,如果这是一个好处,或者如果有任何其他已知的方式来减轻GC在这种情况。也欢迎有效管理可重用对象缓存的想法。

+2

“众多潜在对象的大缓存”==池。 – 2009-08-05 10:45:27

+0

pool ==“没有那么多的乐趣说”:P – izb 2009-08-05 10:48:06

回答

2

通常情况下,我会说这是为调整VM的GC参数作业时,降低了高低不平的烦躁,但是对于移动应用,是不是一个真正的选择。因此,如果您使用的JVMS无法修改GC的行为,那么老式对象池可能是最佳解决方案。

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

6

这与GoF模式手册中详述的flyweight模式类似(请参阅下面的编辑)。 对象池由于在减少对象创建,同步和GC开销方面取得的进展而在“正常”虚拟机中失宠。然而,这些已经有很长一段时间了,尝试看看它们是否有帮助,这当然很好!

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

只有一个测试会告诉你在目标平台上池化方法是否适用于你!

编辑 - 我把OP “再尽可能地使用”意味着该对象是不可改变的。当然这可能并非如此,flyweight模式实际上是关于不可变对象被共享的(Enum是flyweight的一个例子)。可变(读取:不可共享)对象不是flyweight模式的候选对象,但当然是对象池。

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 
0

鉴于this答案表明在J2ME中调整垃圾回收本身的空间不大,如果GC是一个问题,唯一的其他选择是查看如何更改应用程序以改进性能/内存使用情况。也许在引用的答案中的一些建议将适用于您的应用程序。

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

1

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

“并发标记扫描收集器,也称为并发收集器或CMS,针对对垃圾收集暂停敏感的应用程序。” “在JDK 6中,CMS收集器可以同时执行这些集合,以避免响应System.gc()或Runtime.getRuntime()。gc()调用的冗长暂停。此功能,添加选项“

-XX:+ExplicitGCInvokesConcurrent 
2

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

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

2

J2ME是否有世代垃圾回收器?如果是这样,它会做很多小而快的收藏,因此停顿时间会缩短。您可以尝试减少伊顿内存空间(小内存空间)以增加频率并减少集合的延迟,从而减少暂停。

虽然,想一想,我的猜测是你不能调整gc行为,因为一切可能运行在同一个虚拟机中(这里只是一个猜测)。

1

结账this link。特别是:

只是列出几个 对象池创建问题:第一,未使用的 对象占用的没有 理由内存空间; GC必须处理未使用的 对象,并将其无条件地扣留在 无用对象上;和在 以便获取从 对象池的同步是 通常需要比所述异步分配 可用本身慢得多 的对象。