1

我有一个运行 OOM 的应用程序,它有大量可用的可用堆空间,并且可以在现有的 Galaxy S3 上增长。该应用程序在其他设备上运行良好。

知道在传统 Java 中这可能是由永久代空间中的 OOM 引起的,我尝试研究 Dalvik 如何处理这个问题,但找不到任何确定的东西。Androids SDK 似乎缺少 MemoryUsage 和 ManagementFactory,所以我无法像在 Java 中那样得到它们。

我试图找出Android是否有永久代空间,我可以检查它的内容,我如何获得大小和空闲,Dalvik是否处理进入这个空间的东西不同于JVM,等等。

如果这个空间不存在或不太可能,也可以接受其他想法。

关于应用程序的一些信息。运行 OOM 的 S3 正在运行 4.1.2。该应用程序使用大约 12-25 MB 的堆,可用的最大堆大小约为 45 MB。它有很多本地资源图像,稍后会延迟加载更多。我正在 .recylce() 处理位图。该应用程序每次都在大致相同的位置崩溃。我仔细查看了崩溃点周围的代码,我没有看到任何不寻常的地方。其他设备运行此代码就好了。

4

1 回答 1

1

在我看来,您遇到了堆碎片问题。

您在具有大量可用空间的堆中分配 1.2MB 失败。系统可能无法找到 1.2MB 的连续空块,因为您的堆已完全碎片化,并且无法进一步扩大您的堆。

从理论上讲,您不应该担心碎片问题,并且自动 GC 会为您处理它。

实际上,我不止一次看到,为系统 GC 提供帮助有时会取得出色的效果。

以下是解决碎片问题的一些想法:

  1. System.gc()在战略位置手动运行。热门地点是在销毁大型对象期间,例如活动 onDestroy。其他地方是在像位图这样的大分配之前。在解码任何大型位图之前,请添加手动 GC。如果以后想减少 GC 的数量,请通过查询各种堆大小函数来手动测试有问题的内存条件。

  2. 协助 System GC 更快释放资源。这将首先防止您的堆变得碎片化。网上有很多关于如何做到这一点的材料。一些从我的头顶:

    • 如果您有频繁的小分配,请尝试采用内存重用方案,例如创建一个对象池,并重用池中的对象而不是分配新的对象。这种优化经常出现在 android 适配器中(比如 listviews 中的视图重用)
    • 当您不需要变量时手动将它们设置为 null,以便显式断开它们与参考图的连接并标记它们以便于 GC(显式清除数据集合也是如此)
    • 当你有大量操作时避免不可变类,比如字符串的连接,使用StringBuilder而不是常规String的 s
    • 完全避免终结器
    • 避免循环引用,或者至少将其中一个更改为弱引用
    • 一般在需要的地方使用弱引用

你可以通过确保你的堆在你只使用它的一小部分时不会增长到巨大的大小来衡量你的成功程度。

另一个想法是尝试使 1.2MB 分配更小。通过使用更小的图像或在解码期间重新缩放它们。

于 2013-07-30T06:32:08.900 回答