Android堆内存大小看起来不正确

时间:2012-01-20 17:21:22

标签: android memory imageview heap

我有一个Android应用程序,显示很多图像,它工作,图像从网址收集,添加到一个阙,由4个线程收集,存储在缓存中,然后显示在列表视图中4个图像为行,屏幕上每次都有六行。通常总共有90张图片。

行(和图像视图)总是被回收,所以项目的数量总是相同的,我没有初始化任何东西。

这似乎工作得很好,我的平均使用堆大小总是13MB。

我遇到的问题是,一开始mi max heap size非常小,我得到的GC消息如下:

  

01-20 16:48:39.191:D / dalvikvm(9743):GC_FOR_ALLOC被释放< 1K,31%自由12048K / 17351K,暂停25ms

但是我向上滚动的视图越多,堆大小变得越来越无用,我得到像

这样的东西
  

01-20 17:02:05.339:D / dalvikvm(11730):GC_FOR_ALLOC释放544K,72%免费13871K / 49159K,暂停35ms

如你所见即使使用的是相同的,即使我没有达到那个限制,最大值也会增加。而真正的问题是,此时我开始出现内存错误。

有人可以解释我的错误吗?

谢谢!

3 个答案:

答案 0 :(得分:0)

您使用的是哪个版本的Android?如果您在3.0之前(即2.x)进行测试,那么在Bitmaps中存储大部分信息的字节数组将被分配并存储在本机内存中。这意味着在堆转储和GC通知中,您只能看到位图中用于指针的少量内存,而不是实际大小。

有关详细信息,请查看有关内存管理和检测内存泄漏的Google IO讨论:http://www.youtube.com/watch?v=_CruQY55HOk

此外,我还参与了几个类似的应用程序。我的猜测是你的缓存大小太大,或者(更有可能)你正在显示和存储在缓存中的图像远大于你实际想要的大小。如果在图像视图中显示位图,则imageview会将原始位图存储在内存中,即使它远大于视图中实际适合的位图。尝试将图像从磁盘调整到至少接近适当大小的尺寸,然后再尝试显示它们:How do I scale a streaming bitmap in-place without reading the whole image first?

答案 1 :(得分:0)

要缓存我的图片,请使用Map<String, Drawable> drawableMap。在OutOfMemoryError上我调用此函数:

private void cacheLeeren()
{
    int size = drawableMap.size();
    int del = (int) (size * 0.3);
    Set<String> s = drawableMap.keySet();
    for (String t : s)
    {
        if (del >= 0)
        {
            drawableMap.put(t, null);
            del--;
        }
    }
}

我认为这不是最好的方式......但它有效; - )

答案 2 :(得分:0)

我的猜测是您的应用在短时间内达到了非常高的内存使用峰值。确实,平均而言你只使用13MB,但如果你的堆增长到50MB,那就意味着你已经消耗了比你想象的更多的内存。

让我们试着弄清楚这是怎么回事。您已经提到过您正在使用LRU缓存。该缓存在填满后立即释放内存。我的猜测是你开始释放内存太晚,而且这个内存不会立即释放 - 因为它取决于系统GC。每当您从缓存中释放某些项目时,请尝试手动调用System.gc()

您还提到过您正在呼叫Bitmap.recycle()。据我所知,这在Android 3+上没用,因为本机堆不再用于位图。由于所有位图都在dalvik堆上,因此GC将释放它们。除非您自己调用System.GC(),否则不能像以前那样匆匆忙忙。

问题来源的另一个想法是堆碎片。请参阅我之前对此question中类似问题的回答。