【问题标题】:How to avoid OutofMemoryException?如何避免 OutofMemoryException?
【发布时间】:2012-08-29 14:10:34
【问题描述】:

我的应用程序中的活动包含片段,而片段又包含充满位图数据的列表视图/网格视图。最终用户将耗尽内存,因为先前活动的视图及其片段没有被破坏。因此,当用户达到第 10 个活动时 - 前 9 个活动持有大量位图数据。

我已经在使用弱引用,但是 MAT 表示某些片段的视图包含对例如 Gallery 的引用,而 Gallery 又包含适配器等。因此 ImageViews 保持活动状态,位图也是如此。

到目前为止,我已经尝试过完全移除片段、移除适配器。有时它可以工作,但我想知道为什么这会如此复杂,是否有任何更简单的方法可以在没有太多编码的情况下释放/获取?

UPD

我会很感激有一个开源应用程序的例子,其中遇到了同样的问题。

UPD2

我的大部分活动的蓝图是:活动持有片段。片段包含充满图像视图的 AbslistView。

谢谢。

【问题讨论】:

  • 不看代码真的很难判断。
  • 如果您的 ImageViews 仍然存在,您应该仔细检查适配器中的回收。观看次数应该与您在屏幕上看到的大致相同。
  • 我不回收它们 - 我应该吗?我的意思是,如果我回收它们,那么它会抛出有关图像视图缺少的帧的异常。这里有什么解决方法吗?
  • 适配器应该总是回收视图。搜索viewholderconvertview
  • 假设您在需要时动态创建Bitmaps,并且您只为ListView 中的每一行使用唯一的位图实例,如果您在@ 中找到一个,您应该能够recycle() 它们987654326@。但是在这种情况下,通过 GC 自动回收对我来说效果很好,因为在显示列表时一次只需要很少的小位图。只是没有ArrayList<Bitmap> 或列表中每个项目的图像等效项。

标签: android memory


【解决方案1】:

如果不耗尽所有内存,很难完成它。

这需要按需(重新)加载、在视图销毁时释放内存以及仔细设计片段和类。

https://developer.android.com/training/displaying-bitmaps/index.html 提供了一些有关以这种方式加载图像的宝贵信息。

如果您通过某种异步缓存加载程序加载所有图像,请根据您的需要清除 onViewDestroyedonDetached 上的缓存,并且不要保留对这些位图的其他引用,您应该已经解决了大部分问题.

生命周期非常对称(onCreateonDestroy,...),因此最好将您在该生命周期部分的另一侧创建的任何引用清空。假设您在生命周期中使用适当的位置,您将免费获得大量内存管理。在您的情况下,您应该检查以防您的片段被保留,您不会保留对GalleryImageViews 的引用(应该只存在于onCreateView -> onDestroyView 之间)

【讨论】:

  • 深入来说,我的应用可以包含 10 个甚至更多的活动。在导航到第 10 个活动时,以前的片段的 onDestroyView 永远不会被调用。是否有任何解决方法可以手动回收位图并恢复它们以防止帧异常?我会很感激一个例子
  • 没有示例 :( “以前的片段”onDestroyView 永远不会被调用”,一旦您离开活动,就不应该发生 - “当与片段关联的视图层次结构正在被调用时调用已删除。” 部分应该触发。但如果有办法防止这种情况,除了杀死应用程序
【解决方案2】:

我建议只保留你需要的内存并销毁其他所有内容。用完所有可用内存是不好的形式。我会查看活动生命周期并完全理解它以解决您的问题: https://developer.android.com/reference/android/app/Activity.html

【讨论】:

  • 你知道任何使用弱引用并基本上处理内存管理的开源应用程序示例吗?
  • 我没有。仅按照您所说的进行,我将销毁 onPause() 中的所有引用,并在每个活动的 onResume() 事件中重新创建它们。这样,只有当前的活动引用会在内存中。此外,如果您不这样做并且您的应用程序被暂停 - 来电等 - 并且您的应用程序被操作系统杀死,那么您刚刚泄漏了所有内存。
【解决方案3】:

我建议观看 Memory management for Android apps Google IO 2011 演示文稿。

您还应该检查应用的工作流程,以确定何时可以开始销毁旧 Activity 或释放其他资源。

您还可以使用ActivityManager.getProcessMemoryInfo() 检索您的进程的内存使用信息,以帮助确定您是否需要释放一些旧资源。

【讨论】:

  • 所以你想说它仍然是一种手动方法,Android 不会使用说 LRU 算法来破坏视图/免费位图?
  • Android 在本机上应该可以很好地完成这方面的工作,但是如果不看代码就很难诊断出你的问题。如果您要防止旧活动被销毁(例如,停止 onDestroy()),那么您正在干扰内置的内存释放过程。但是,是的,Android 确实将大量内存管理责任交给了开发人员。
  • 虽然这听起来很老派,但良好的内存管理仍然由程序员承担。你最了解你的应用程序。您必须问自己在任何给定时间点真正需要什么,并摆脱其他任何事情 - 不要依赖操作系统为您做这件事。
【解决方案4】:

如果您的内存不足异常发生在适配器的 getView 方法中,

你可以隔离它通常发生的行,并用这样的 try-catch 包围它:

try {
   // load image (or whatever your loadimage is)
    mViewHolder.thumbImage.loadImage();
} catch (OutOfMemoryError e) {
   // clear your image cache here if you have one
   // call gc
   System.gc();
   // load image retry
   mViewHolder.thumbImage.loadImage();
}

它不是世界上最优雅的解决方案,但它应该会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-14
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多