java - Android 并在剩余可用堆空间的情况下运行 OOM

标签 java android memory-management

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

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

我试图查明 Android 是否有一个永久生成空间,我可以检查它的内容,我怎样才能获得大小和自由,Dalvik 处理这个空间的内容是否与 JVM 不同,等等。

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

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

最佳答案

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

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

理论上,您不必担心 fragment 问题,自动 GC 会为您处理。

实际上,我不止一次看到给系统 GC 提供帮助有时会取得非常好的结果。

这里有一些解决 fragment 问题的想法:

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

  2. 协助系统 GC 更快地释放资源。这将首先防止您的堆变得 fragment 化。网上有很多关于如何做到这一点的 Material 。一些来 self 的头顶:

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

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

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

关于java - Android 并在剩余可用堆空间的情况下运行 OOM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17407472/

相关文章:

c++ - 动态内存分配

c++ - 当您不知道确切的元素数量但可以估计上限时,分配比数组所需更多的内存是否可以?

java - 运行我的 java spring-boot 项目时出现 InspirationTargetException

java - spring boot xa事务数据源和jms

java - 重写需要原始类型参数化的方法

java - spring security - 身份验证中的sessionId为空

android - Proguard 不会更改包名称

android - 如何在模拟器中安装 80 MB 大小的应用程序?

java - 一个类中存在两个单击监听器的问题

java - java中的对象头和填充是什么