ChatGPT解决这个技术问题 Extra ChatGPT

Android 中的垃圾收集器

我见过许多建议在某些情况下调用垃圾收集器的 Android 答案。

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

在求助于垃圾收集器之前我还应该使用其他东西吗?


F
Fabian Zeindl

对于 3.0 蜂窝 之前的版本:是的,调用 System.gc()

我尝试创建位图,但总是收到“VM 内存不足错误”。但是,当我第一次调用 System.gc() 时,一切正常。

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

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

所以我建议在创建位图之前手动调用 System.gc()


这是因为 pre-honeycomb,位图数据没有存储在 VM 中,因此不会触发 GC。在 Honeycomb 及以后的版本中应该不是问题。
@Timmmm 但这实际上是我的问题,我只是将 largeheap 设置为 true。
T
Thomas Pornin

一般来说,在存在垃圾收集器的情况下,手动调用 GC 绝不是一种好习惯。 GC 是围绕启发式算法组织的,这些算法在留给自己的设备时效果最好。手动调用 GC 通常会降低性能。

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


+1 以获得良好的独立于平台的答案。在选择之前等待看看是否有人提出了特定于 Android 的答案。
如果您允许“性能”意味着比 CPU 效率更普遍的东西,我同意您所写的内容。在 Android 设备上,用户对性能的感知至关重要。例如,开发人员可能更喜欢在用户按下按钮时运行 GC,这样用户就不会意识到 GC。
游戏运行时不运行 GC 通常在游戏中很重要(这需要预先创建和回收所有对象或类似的),但是当游戏暂停时,这是 GC 的好时机。
预蜂窝,位图数据不存储在 VM 内存中。系统不会检测到您何时因位图而使用了过多的非 VM 内存并运行 GC(这将运行释放非 VM 内存的 Bitmap.finalize() 方法)。因此,在这种情况下,您应该越过 GC 的头脑并在适当的地方运行 Bitmap.recycle()System.gc()。但只是预蜂窝。
@ThomasPornin - 另一方面,作为应用程序程序员,您知道操作系统不知道的一些事情:您的应用程序现在将在其使用内存的方式上做出重大改变的时间,并且它对用户体验现在暂停,而不是将来的任意时间。这意味着在应用程序的使用方式发生重大转变时,偶尔拨打电话可能是明智的。从不应该频繁调用 GC 的意义上说,这些情况很少见,但很常见,因为几乎所有重要的应用程序都有这样的已知设计时刻。
s
stkent

如果我们没有正确处理位图,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 会导致短暂的“暂停”,因此不建议在每次分配位图之前执行此操作。

最佳设计是:

通过显示的 if/recycle/nullcode 释放所有不再需要的位图。 (制作一种方法来帮助解决这个问题。) System.gc();分配新的位图。


A
Artem Russakovskii

如果你得到一个 OutOfMemoryError ,那么调用垃圾收集器通常为时已晚......

以下是来自 Android 开发者的引用:

大多数情况下,垃圾收集的发生是因为大量的小而短暂的对象和一些垃圾收集器,如分代垃圾收集器,可以优化这些对象的收集,以便应用程序不会经常被中断。不幸的是,Android 垃圾收集器无法执行此类优化,因此在性能关键代码路径中创建短期对象对您的应用程序来说代价非常高昂。

所以据我了解,没有迫切需要调用gc。最好花更多的精力来避免不必要的对象创建(例如在循环内创建对象)


不能以其他方式解释报价吗?也许需要手动调用 GC 以便在这些对象消耗过多内存之前收集它们。
@hgpc:我看不出如何以您建议的方式解释报价。我猜文档是一个供词,承认他们的 GC 很简单;当内存不足时,将执行完整的 GC。
充分利用复杂对象和使用复杂对象的框架往往比过早优化更能利用开发时间。与 Enterprise Java 相比,担心优化对于 Android 来说是一个更容易陷入的陷阱,因为我们在编写移动应用程序时会下意识地考虑性能。特别是作为框架开发人员,他们必须考虑性能,当他们不小心时,会将该观点泄漏到他们的官方文档中。
c
cmicat

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


System.gc()Runtime.getRuntime().gc() 的包装函数。请参阅android.googlesource.com/platform/libcore/+/…
是的,从源代码和文档看来它们是相同的,但确实 System.gc() 对我不起作用,但 Runtime.getRuntime().gc() 可以!
K
Klykoo

我的应用程序管理了很多图像,并因 OutOfMemoryError 而死。这对我有帮助。在 Manifest.xml 添加

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

谷歌不喜欢这个
@PedroPauloAmorim 解释为什么?
除非您确定自己在做什么,否则不要使用 largeHeap。使用大堆会使垃圾收集器的工作更加困难,因为它必须在清除内存之前遍历大量垃圾数据。
P
Paramjit Singh Rana

一般来说,您不应该使用 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)有义务响应的命令。认为它更像是对虚拟机说“如果不麻烦,请您进行垃圾收集”。


p
prabhu

在位图创建期间避免 OOM 的最佳方法,

http://developer.android.com/training/displaying-bitmaps/index.html


F
Farbod Salamat-Zadeh

我会说不,因为 Developer docs on RAM usage 状态:

... GC_EXPLICIT 显式 GC,例如当您调用 gc() 时(您应该避免调用,而是信任 GC 在需要时运行)。 ...

我用粗体突出了相关部分。

看看 YouTube 系列,Android Performance Patterns - 它将向您展示管理应用程序内存使用的技巧(例如使用 Android 的 ArrayMapSparseArray 而不是 HashMap)。


D
Denis Gordin

Xamarin 开发人员的快速说明。

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


C
Christian Seifert

OutOfMemoryError 之后无需调用垃圾收集器。

它的 Javadoc 明确指出:

当 Java 虚拟机因为内存不足而无法分配对象时抛出,并且垃圾收集器无法提供更多内存。

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


Android Javadoc 没有说明这一点,而且很可能它的实现是不同的。 d.android.com/reference/java/lang/OutOfMemoryError.html
你是对的,这不适用于Android。但是话又说回来,您无法在运行时以太处理 OOE,因此即使这是/不是真的,您也无能为力。