我见过许多建议在某些情况下调用垃圾收集器的 Android 答案。
在执行需要大量内存的操作之前请求 Android 中的垃圾收集器是一种好习惯吗?如果不是,我是否应该只在收到 OutOfMemory
错误时才调用它?
在求助于垃圾收集器之前我还应该使用其他东西吗?
对于 3.0 蜂窝 之前的版本:是的,调用 System.gc()
。
我尝试创建位图,但总是收到“VM 内存不足错误”。但是,当我第一次调用 System.gc()
时,一切正常。
创建位图时,Android 经常会因内存不足错误而失败,并且不会先尝试进行垃圾收集。因此,调用 System.gc()
,您就有足够的内存来创建位图。
如果创建对象,我认为 System.gc
会在需要时自动调用,但 不会 用于创建位图。它只是失败了。
所以我建议在创建位图之前手动调用 System.gc()
。
一般来说,在存在垃圾收集器的情况下,手动调用 GC 绝不是一种好习惯。 GC 是围绕启发式算法组织的,这些算法在留给自己的设备时效果最好。手动调用 GC 通常会降低性能。
有时,在一些相对罕见的情况下,人们可能会发现特定的 GC 出错了,然后手动调用 GC 可能会在性能方面有所改善。这是因为实际上不可能实现一个“完美”的 GC 来在所有情况下都以最佳方式管理内存。这种情况很难预测,并且取决于许多微妙的实现细节。 “好的做法”是让 GC 自己运行;手动调用 GC 是一个例外,只有在适当地见证了实际性能问题之后才能设想。
Bitmap.finalize()
方法)。因此,在这种情况下,您应该越过 GC 的头脑并在适当的地方运行 Bitmap.recycle()
或 System.gc()
。但只是预蜂窝。
如果我们没有正确处理位图,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;
有关更多信息,请查看此链接
注意:由于执行 gc 会导致短暂的“暂停”,因此不建议在每次分配位图之前执行此操作。
最佳设计是:
通过显示的 if/recycle/nullcode 释放所有不再需要的位图。 (制作一种方法来帮助解决这个问题。) System.gc();分配新的位图。
如果你得到一个 OutOfMemoryError ,那么调用垃圾收集器通常为时已晚......
以下是来自 Android 开发者的引用:
大多数情况下,垃圾收集的发生是因为大量的小而短暂的对象和一些垃圾收集器,如分代垃圾收集器,可以优化这些对象的收集,以便应用程序不会经常被中断。不幸的是,Android 垃圾收集器无法执行此类优化,因此在性能关键代码路径中创建短期对象对您的应用程序来说代价非常高昂。
所以据我了解,没有迫切需要调用gc。最好花更多的精力来避免不必要的对象创建(例如在循环内创建对象)
似乎 System.gc()
在 Art Android 6.0.1 Nexus 5x 上不起作用,所以我改用 Runtime.getRuntime().gc();
。
System.gc()
对我不起作用,但 Runtime.getRuntime().gc()
可以!
我的应用程序管理了很多图像,并因 OutOfMemoryError 而死。这对我有帮助。在 Manifest.xml 添加
<application
....
android:largeHeap="true">
一般来说,您不应该使用 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 版本(我认为是 Pre 3.0)通常需要它,但以后的版本不需要它。此外,在较新版本上使用它也不会造成太大伤害(只是不要在循环中执行此操作或类似的操作)。新的 ART 运行时在这里发生了很大变化,因为他们为大对象引入了一个特殊的堆“分区”,但我认为使用 ART ether 这样做不会有太大的伤害。
还有一个关于 System.gc() 的非常重要的说明。此方法不是 Dalvik(或 JVM)有义务响应的命令。认为它更像是对虚拟机说“如果不麻烦,请您进行垃圾收集”。
我会说不,因为 Developer docs on RAM usage 状态:
... GC_EXPLICIT 显式 GC,例如当您调用 gc() 时(您应该避免调用,而是信任 GC 在需要时运行)。 ...
我用粗体突出了相关部分。
看看 YouTube 系列,Android Performance Patterns - 它将向您展示管理应用程序内存使用的技巧(例如使用 Android 的 ArrayMap
和 SparseArray
而不是 HashMap
)。
Xamarin 开发人员的快速说明。
如果您想在 Xamarin.Android 应用程序中调用 System.gc()
,您应该调用 Java.Lang.JavaSystem.Gc()
OutOfMemoryError
之后无需调用垃圾收集器。
它的 Javadoc 明确指出:
当 Java 虚拟机因为内存不足而无法分配对象时抛出,并且垃圾收集器无法提供更多内存。
因此,垃圾收集器在产生错误之前已经尝试释放内存但没有成功。