我有一个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
如你所见即使使用的是相同的,即使我没有达到那个限制,最大值也会增加。而真正的问题是,此时我开始出现内存错误。
有人可以解释我的错误吗?
谢谢!
答案 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中类似问题的回答。