Android中的垃圾收集器


108

我已经看到许多Android答案,建议在某些情况下调用垃圾回收器。

在执行需要大量内存的操作之前,在Android中请求垃圾收集器是一种好习惯吗?如果没有,我应该仅在遇到OutOfMemory错误时才调用它吗?

在诉诸垃圾收集器之前,我还应该使用其他东西吗?

Answers:


144

对于3.0 Honeycomb之前的版本:是,请致电 System.gc()

我试图创建位图,但始终出现“ VM内存不足错误”。但是,当我System.gc()第一次打电话时,还可以。

创建位图时,Android经常会因内存不足错误而失败,并且不尝试首先进行垃圾回收。因此,调用System.gc(),您就有足够的内存来创建位图。

如果创建对象,我认为System.gc会在需要时自动调用,而不是用于创建位图。它只是失败。

因此,我建议System.gc()在创建位图之前手动调用。


39
这是因为蜂窝前的位图数据未存储在VM中,因此不会触发GC。在Honeycomb及更高版本中,这应该不是问题。
Timmmm 2012年

2
@Timmmm,但这实际上是我的问题,我只是将largeheap设置为true。
雷·莱巴

118

一般来说,在存在垃圾收集器的情况下,手动调用GC 永远不是一个好习惯。GC是围绕启发式算法组织的,当将其放在自己的设备上时效果最佳。手动调用GC通常会降低性能。

有时,在某些相对罕见的情况下,可能会发现特定的GC出错了,然后手动调用GC可能会改善性能。这是因为实际上不可能实现在所有情况下都能最佳地管理内存的“完美” GC。这种情况很难预测,并且取决于许多细微的实现细节。“好的做法”是让GC自己运行;手动调用GC是个例外,只有在实际见证了实际性能问题之后,才可以设想到此。


8
+1是一个独立于平台的良好答案。在选择之前,请先等待是否有人提出了Android专用的答案。
hpique 2010年

8
我同意您所写的内容,如果您允许“性能”表示比CPU效率更一般的含义。在Android设备上,用户对性能的看法至关重要。例如,在用户按下按钮时,开发人员可能更喜欢运行GC,因此用户将不会意识到GC。
总统詹姆斯·波尔克(James K. Polk)2010年

5
在游戏中通常很重要的一点是,GC不能在游戏运行时运行(这要求所有对象都是预先创建的并且可以回收或类似的),但是当游戏暂停时,这是GC的好时机。
2012年

4
蜂窝前,位图数据未存储在VM内存中。由于位图的原因,系统将无法检测到您何时使用了过多的非VM内存并运行GC(GC将运行Bitmap.finalize()释放非VM内存的方法)。因此,在这种情况下,您应该越过GC的头部并运行Bitmap.recycle()System.gc()在适当的地方运行。但只有蜂巢前。
Timmmm 2012年

1
@ThomasPornin-另一方面,作为应用程序程序员,您知道操作系统不知道的一些信息:您的应用程序现在将对其内存使用方式进行重大更改的时间,并且对应用程序的破坏性较小用户体验现在需要暂停,而不是将来的任意时间。这意味着在应用程序的使用方式发生重大转变时不经常拨打电话是明智的。从很少有人应该不经常调用GC的角度来看,这些很少见,但是它们的共同之处在于,几乎所有重要的应用程序都具有这种设计已知的时刻。
ToolmakerSteve

26

如果我们不能正确处理位图,则在android应用程序中内存不足是很常见的,解决该问题的方法是

if(imageBitmap != null) {
    imageBitmap.recycle();
    imageBitmap = null;
}
System.gc();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 3;
imageBitmap = BitmapFactory.decodeFile(URI, options);
Bitmap  scaledBitmap = Bitmap.createScaledBitmap(imageBitmap, 200, 200, true);
imageView.setImageBitmap(scaledBitmap);

在上面的代码中,刚刚尝试回收位图,这将使您释放已使用的内存空间,因此可能不会发生内存不足的情况。

如果仍然遇到问题,您也可以添加这些行

BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16*1024];
options.inPurgeable = true;

有关更多信息,请查看此链接

https://web.archive.org/web/20140514092802/http://voices.yahoo.com/android-virtual-machine-vm-out-memory-error-7342266.html?cat=59


注意:由于执行gc会导致短暂的“暂停”,因此建议在每次分配位图之前执行此操作。

最佳设计是:

  1. 通过显示的代码释放不再需要的所有位图if / recycle / null。(为此提供一种帮助方法。)

  2. System.gc();

  3. 分配新的位图。


19

如果出现OutOfMemoryError错误,那么调用垃圾回收器通常为时已晚...

这是来自Android Developer的报价:

在大多数情况下,垃圾收集是由于大量的小型短期对象而发生的,某些垃圾收集器(如分代垃圾收集器)可以优化这些对象的收集,以使应用程序不会被频繁中断。不幸的是,Android垃圾收集器无法执行此类优化,因此,在性能关键代码路径中创建短期对象对于您的应用程序而言非常昂贵。

因此,据我了解,没有紧急需要致电gc。最好花更多的精力避免不必要的对象创建(例如在循环内创建对象)


6
引用不能以其他方式解释吗?也许需要手动调用GC,以便在这些对象消耗过多内存之前收集它们。
hpique 2010年

@hgpc:我看不到如何以您建议的方式解释报价。我猜这个文档是坦白的,承认他们的GC很简单。当内存不足时,将执行完整的GC。
总统James K. Polk 2010年

与过早的优化相比,充分利用复杂的对象和使用复杂的对象的框架倾向于更好地利用开发时间。与企业Java相比,与Android相比,与Android相比,担心优化更容易陷入陷阱,因为我们在编写移动应用程序时潜意识地一直在考虑性能。特别是当框架开发人员不得不考虑性能时,如果他们不小心,就会将该观点泄漏到他们的官方文档中。
LateralFractal 2014年

9

似乎System.gc()在Art Android 6.0.1 Nexus 5x上不起作用,因此我Runtime.getRuntime().gc();改用了。


1
System.gc()是的包装函数Runtime.getRuntime().gc()。见android.googlesource.com/platform/libcore/+/...
弥敦道F.

是的,从源头和文档看来,它们是相同的,但确实System.gc()对我不起作用,但是Runtime.getRuntime().gc()可以!
伊万

7

我的应用程序管理大量图像,但由于OutOfMemoryError而死亡。这对我有帮助。在Manifest.xml中添加

<application
....
   android:largeHeap="true"> 

9
谷歌不喜欢这样
佩德罗·保罗·阿莫林

1
@PedroPauloAmorim解释为什么?
马查多

2
除非您确定自己在做什么,否则不要使用largeHeap。使用大堆会使垃圾回收器工作起来更加困难,因为它必须在清除内存之前循环遍历大量垃圾数据。
Prakash 2015年

7

一般来说,您不应使用System.gc()显式调用GC。甚至在IO讲座(http://www.youtube.com/watch?v=_CruQY55HOk)上,他们都解释了GC暂停日志的含义,并且在其中他们还声明从不调用System.gc(),因为Dalvik更了解比您什么时候这样做。

另一方面,如上文所述,Android中的GC流程(像其他所有流程一样)有时会出现问题。这意味着Dalvik GC算法不能与Hotspot或JRockit JVM相提并论,在某些情况下可能会出错。这些情况之一就是分配位图对象时。这是一个棘手的问题,因为它使用堆和非堆内存,并且因为内存受限设备上的一个位图对象的松散实例足以给您OutOfMemory异常。因此,许多开发人员通常建议在不再需要该位图后调用它,甚至被某些人认为是一种好习惯。

更好的做法是在位图上使用.recycle(),因为这样做是为了实现此方法,因为它将位图的本机内存标记为可以安全删除。请记住,这是非常依赖于版本的,这意味着通常在较旧的Android版本(我认为是3.0之前的版本)上是必需的,而在更高版本上则不需要。同样,在较新版本的ether上使用它也不会造成太大伤害(只是不要循环执行或类似操作)。新的ART运行时在这里发生了很大的变化,因为它们为大型对象引入了特殊的堆“分区”,但是我认为使用ART ether这样做不会有多大伤害。

也是有关System.gc()的非常重要的说明。此方法不是Dalvik(或JVM)必须响应的命令。认为它更像是对虚拟机说“如果没有麻烦,请您进行垃圾收集”。




3

Xamarin开发人员快速说明。

如果您想System.gc()在Xamarin.Android应用中调用,则应调用Java.Lang.JavaSystem.Gc()


2

结束后无需调用垃圾收集器OutOfMemoryError

Javadoc明确指出:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

因此,垃圾收集器在产生错误之前已经尝试释放内存,但是没有成功。


8
Android Javadoc并未声明这一点,很可能其实现方式有所不同。d.android.com/reference/java/lang/OutOfMemoryError.html
hpique 2010年

您是正确的,这不适用于Android。但是话又说回来,您不能在运行时以太上处理OOE,因此即使事实并非如此,您也无法做很多事情。
IgorČordaš2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.