小型对象的池是否比Android的Java垃圾收集器更高效?

时间:2013-06-13 22:47:02

标签: java android garbage-collection

所以,我正在读这个:http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html 其中说:“公共服务公告:对象池现在是一个严重的性能损失,除了最重量级的对象之外的所有对象,即使这样,在不引入并发性瓶颈的情况下做到正确也很棘手”,并将其视为面值。本文讨论了分代GC,解除分配,线程局部分配和转义分析。

然而,我脑子里只有一个小小的声音问我,“但这对Android中的垃圾收集器实现是否正确?”而且我不知道答案。我甚至都不知道如何找到答案。

我记得当我为经常使用的小对象实现池化时,我的Android应用程序中GC的运行频率较低。不确定这是否意味着更快的应用程序..此外,GC运行更频繁而没有池(根据logcat),所以我认为Android的GC实现失去了汇集..但这个假设几乎没有支持,因为我没有注意到任何显着的性能差异,无论是否合并。

那么..这里的任何人都知道,对于经常使用的小物件,池化是否比Android的GC效率更高?

2 个答案:

答案 0 :(得分:5)

  

此处的任何人都知道,对于经常使用的小型对象,池化是否比Android的GC效率更高?

这取决于你如何衡量“有效”,“小”和“经常”。

对象池在Android本身的几个地方使用,例如:

  • AdapterAdapterView和kin)的整个ListView框架是围绕对象池设计的,这次是针对相对较重的对象(例如,ListView行很容易就是几十KB)

  • SensorEvent个对象被回收,这次对于每秒可能使用数十次的轻量级对象

  • {li>

    AttributeSet个对象被回收,作为View通胀的一部分

等等。

其中一些是基于早期版本的Dalvik早期版本的Android,当时我们的目标是使用纯粹的解释语言和相当天真的GC引擎,在100MHz以下的CPU。

然而,即使在今天,对象池还有一个超越即时性能的巨大优势:堆碎片。

Java的GC引擎是一个压缩垃圾收集器,意味着连续的空闲堆空间块被组合成更大的块。 Dalvik的GC引擎是一个非压缩垃圾收集器,这意味着您分配的块永远不会成为更大块的一部分。这是许多开发人员搞砸位图管理的地方 - 他们得到的OutOfMemoryError不是因为堆空间不足,而是由于堆碎片,堆没有足够大的块来进行所需的分配。 / p>

对象池避免了堆碎片,只是通过防止池化对象再次收集垃圾并且不经常为池分配新对象(仅当池由于同时使用太多而需要增长时)。

游戏开发人员长期以来一直使用Android中的对象池,这源于Android的垃圾收集非并发时的回归,当GC进行时“停止世界”。现在,大多数Android设备都使用并发垃圾收集器,这可以缓解一些人的痛苦。

因此,对象池肯定是一种相关的技术。但是,大多数情况下,我认为它可以用作对检测到的问题的反应(例如,Traceview在GC中显示太多时间,Traceview在对象构造函数中显示太多时间,MAT显示您有足够的堆但是你得到OutOfMemoryErrors)。例外是游戏开发 - 游戏开发者可能有自己的启发式方法,因为现代Android设备仍需要池化。

答案 1 :(得分:2)

你的推理存在谬误。更频繁地运行GC并不表示某种性能下降。那些更频繁的GC运行也可能比那些不得不混淆对象池的频率更快,寿命更短。

那就是说,我做了一些研究,这里有一些想法...... 几年前,我的手机只有一个核心。运行GC意味着从活动切换到GC线程。即使使用并发GC和多核(现代设备有2-5个afaik),也可能会有轻微的暂停。

对于下一个交互序列,预先分配用户可能需要的所有内容都是游戏的好主意。基本上遵循实时应用程序的咒语,与在应用程序的用户体验部分具有一致的可测量性能相比,对整体性能的担忧较少。

http://developer.android.com/training/articles/perf-tips.html