安卓内存溢出预防

9

我有一个列表,显示从网上实时下载的缩略图(小图片)。

但是在某个时刻,这个过程会耗尽内存。

我该如何判断可用内存即将耗尽,以便停止下载更多的图片?

我希望提前知道这一点,以免处于内存不足的边缘。

注意: 这不是内存泄漏,只是下载了大量的位图。

谢谢。


我再详细解释一下。为了避免重复下载每个图像,我在活动中缓存已下载的图像,并替换旧的图像 - LRU。我想知道何时停止缓存或限制LRU的大小。 - AlikElzin-kilaka
我遇到了同样的问题,我尝试了软引用以及其他方法... - user468311
4个回答

27

1) 自己做浏览器。

将缩略图下载到SD卡,而不是保存在RAM中。在保存它们之前缩小/旋转它们,以便在下次加载它们时,从SD卡而不是互联网加载是“免费”的。(即像任何浏览器一样,使用本地文件缓存)。

释放任何你可能创建来执行此操作的临时 Bitmap 对象。

学习如何使用 "inSampleSize" 参数解压缩低于原始分辨率的位图。

如果你写的文件以图像扩展名结尾(.jpg等),它们将出现在图库中,因此不要用明显的图像文件名保存缩略图。

2) 创建分层缓存系统(Bitmap > SD卡 > 互联网)。

当你解压缩缩略图时,将其保存在 SoftReference 缓存中。如果你需要使用该缩略图,请从缓存中获取它。如果 VM 需要更多内存,则你的 SoftReference 实例可能返回 null。

如果从位图缓存中获取到 null,则检查是否已将 URL 放在 SD 卡上,并从那里加载到位图缓存中。

如果从文件系统中获取 null,则从互联网下载图像并将其保存到SD卡中,然后将其放入位图缓存中。

3) 释放不再使用的资源。

同样地,确保在 View 不再显示时就从它们所放置的 Bitmaps 中清除它们(如果你的 Views 存在于 ListView 或其他基于 Adapter 的元素中,这基本上是从回收 View 元素中“免费”完成的)-- 然而,如果你实例化了带有 Bitmaps 的 ImageView,并且它们不立即显示在屏幕上,那么你可能会浪费堆空间。

你可以简单地在 ImageView 上调用 setImageBitmap(null);,这样对于 Bitmap 的引用将被删除(因此,如果唯一的引用是 SoftReference,当它不被使用时,它将被回收)。

4) 注意你处于哪个线程。

记住,你必须从非 UI 线程下载位图(我们使用 Service 实例作为意图请求的队列),并且你必须仅在 UI 线程中将位图附加到 View 实例中。

你需要创建一个良好的排队系统,以从 UI 线程之外的所有内容加载到位图缓存中,然后使用 Handler 告诉你的位图缓存在 UI 线程上填充 ImageView。

5) 注意你的下载队列。

如果像我们一样,你有缩略图和全尺寸图像,你需要手动使用优先级队列将图像请求放在缩略图请求之前,或者使用两个不同的 Service(它们分别将它们的独立意向排队)来下载缩略图与完整图片。

否则,你可能会对一屏幕缩略图下载进行排队,但直到所有缩略图都完成后才响应完整图像。

6) 向系统询问你有多少RAM。

  Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
  Debug.getMemoryInfo(memoryInfo);

7) "onLowMemory()" 方法并不会如你所想的那样。

它是用于当用户在手机上运行太多应用程序,操作系统需要从所有正在运行的应用程序中恢复物理内存时使用的。

这与由于加载过多位图而轻松耗尽应用程序 VM 堆完全不同。

据我所知,您将不会收到警告,您将只会崩溃(但您可以使用上述调用跟踪内存信息)。

希望这对尝试智能下载和显示来自互联网的缩略图有所帮助。

mig


重复使用“SoftReference”。现在,推荐使用LruCache。http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html --- “过去,流行的内存缓存实现是使用SoftReference或WeakReference位图缓存,但这不被推荐。从Android 2.3(API Level 9)开始,垃圾收集器更加积极地回收软引用/弱引用,使它们相当无效。” - ToolmakerSteve

3

我使用SoftReference来保存位图对象。列表只需要当前可见的图像。因此,我永远不需要担心空间不足。

缺点是,当我查看图像并向下滚动(导致某些SoftReferences清除位图),然后再次滚动回到同一位置时,图像会再次下载 :(

此外,SoftReferences被清除得非常快。我希望它们能更长时间地保存内部位图。


非常类似于这个答案:https://dev59.com/cnI-5IYBdhLWcg3wQV8Z#1945518 - AlikElzin-kilaka
现在,使用LruCache而不是SoftReferences。这样可以避免您遇到的引用被清除得比您预期的更积极的问题。http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html - ToolmakerSteve

2

在创建位图时,您应该使用BitmapFactory.OptionsinSampleSize选项。

此外,在Android:相册中内存不足异常中的一些提示对我有所帮助,可以检查可用内存。


无论大小,如果我有太多的图像,最终,进程会耗尽内存。 - AlikElzin-kilaka
当然。最终,您必须停留在有限数量的图像上。问题实际上应该是如何尽可能地推动这个限制。 - Rajath

-1

你可以重写 Activity 的 onLowMemory() 方法来处理这种情况的自定义操作。


我不想到达那个点,所以我想定义一些东西,比如:如果使用的内存达到80%,则停止缓存。 - AlikElzin-kilaka
3
我没有使用这个方法,只是收到了OOM异常。 - user468311
在OOM之前没有调用onLowMemory()。 - Rubycon
-1:onLowMemory 是针对所有应用程序的总内存消耗。这不是问题所在。相反,这个应用程序已经达到了其堆限制。onLowMemory 无法解决这个问题。 - ToolmakerSteve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接