通用图片加载器UIL出现内存溢出错误

5

我正在使用UIL来加载远程图像,并填充FragmentStatePagerAdapter中的片段。

我已经阅读了自述文件和常见错误,但是我无法解决这个bug。

以下是配置信息:

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
    .threadPoolSize(1)
    .build();
    ImageLoader.getInstance().init(config);

这里是我展示图片的地方:

public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {


    ImageLoader imgLoader = ImageLoader.getInstance();

    DisplayImageOptions options = new DisplayImageOptions.Builder()
    .showStubImage(R.drawable.loading)
    .cacheOnDisc()
    .resetViewBeforeLoading()
    .bitmapConfig(Bitmap.Config.RGB_565)
    .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
    .build();

    imgLoader.displayImage(this.contentImage, this.imgView, options);

    return layout;
}

这里是我在适配器中销毁片段的位置:

public void destroyItem(ViewGroup container, int position, Object object) {
    if (position >= getCount()) {
        container.removeAllViews();
        FragmentManager manager = ((Fragment) object).getFragmentManager();
        FragmentTransaction trans = manager.beginTransaction();
        trans.remove((Fragment) object);
        trans.commit();
    }
}

最后我遇到的异常如下:

{
06-20 12:09:24.877: E/dalvikvm-heap(17043): Out of memory on a 6345504-byte allocation.
06-20 12:09:24.877: I/dalvikvm(17043): "pool-1-thread-1" prio=4 tid=16 RUNNABLE
06-20 12:09:24.877: I/dalvikvm(17043):   | group="main" sCount=0 dsCount=0 obj=0x42593a48 self=0x6367e778
06-20 12:09:24.887: I/dalvikvm(17043):   | sysTid=17091 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1667639656
06-20 12:09:24.887: I/dalvikvm(17043):   | state=R schedstat=( 4021618000 2254117000 18267 ) utm=341 stm=61 core=0
06-20 12:09:24.887: I/dalvikvm(17043):   #00  pc 00074350  /system/lib/libdvm.so (dvmDumpNativeStack(DebugOutputTarget const*, int)+35)
06-20 12:09:24.887: I/dalvikvm(17043):   #01  pc 00062afe  /system/lib/libdvm.so (dvmDumpThreadEx(DebugOutputTarget const*, Thread*, bool)+557)
06-20 12:09:24.887: I/dalvikvm(17043):   #02  pc 00062bae  /system/lib/libdvm.so (dvmDumpThread(Thread*, bool)+25)
06-20 12:09:24.887: I/dalvikvm(17043):   #03  pc 000298ec  /system/lib/libdvm.so (dvmMalloc(unsigned int, int)+584)
06-20 12:09:24.887: I/dalvikvm(17043):   #04  pc 0007fdfe  /system/lib/libdvm.so (dvmAllocPrimitiveArray(char, unsigned int, int)+93)
06-20 12:09:24.887: I/dalvikvm(17043):   #05  pc 0005357e  /system/lib/libdvm.so
06-20 12:09:24.887: I/dalvikvm(17043):   #06  pc 000798e0  /system/lib/libandroid_runtime.so (GraphicsJNI::allocateJavaPixelRef(_JNIEnv*, SkBitmap*, SkColorTable*)+67)
06-20 12:09:24.887: I/dalvikvm(17043):   #07  pc 000799ae  /system/lib/libandroid_runtime.so (JavaPixelAllocator::allocPixelRef(SkBitmap*, SkColorTable*)+45)
06-20 12:09:24.887: I/dalvikvm(17043):   #08  pc 0004aa18  /system/lib/libskia.so (SkBitmap::allocPixels(SkBitmap::Allocator*, SkColorTable*)+56)
06-20 12:09:24.887: I/dalvikvm(17043):   #09  pc 000cd848  /system/lib/libskia.so (SkPNGImageDecoder::onDecode(SkStream*, SkBitmap*, SkImageDecoder::Mode)+404)
06-20 12:09:24.887: I/dalvikvm(17043):   #10  pc 000c9504  /system/lib/libskia.so (SkImageDecoder::decode(SkStream*, SkBitmap*, SkBitmap::Config, SkImageDecoder::Mode, bool)+168)
06-20 12:09:24.887: I/dalvikvm(17043):   #11  pc 00075a08  /system/lib/libandroid_runtime.so
06-20 12:09:24.887: I/dalvikvm(17043):   #12  pc 000762ac  /system/lib/libandroid_runtime.so
06-20 12:09:24.887: I/dalvikvm(17043):   #13  pc 0001dd8c  /system/lib/libdvm.so (dvmPlatformInvoke+112)
06-20 12:09:24.887: I/dalvikvm(17043):   #14  pc 0005a6e2  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+165)
06-20 12:09:24.887: I/dalvikvm(17043):   #15  pc 000271a0  /system/lib/libdvm.so
06-20 12:09:24.887: I/dalvikvm(17043):   #16  pc 0002b898  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
06-20 12:09:24.887: I/dalvikvm(17043):   #17  pc 00073d2c  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+563)
06-20 12:09:24.887: I/dalvikvm(17043):   #18  pc 00073e04  /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+19)
06-20 12:09:24.887: I/dalvikvm(17043):   #19  pc 000640f4  /system/lib/libdvm.so
06-20 12:09:24.887: I/dalvikvm(17043):   #20  pc 0000dcfc  /system/lib/libc.so (__thread_entry+124)
06-20 12:09:24.887: I/dalvikvm(17043):   #21  pc 0000d8d0  /system/lib/libc.so (pthread_create+172)
06-20 12:09:24.887: I/dalvikvm(17043):   at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-20 12:09:24.887: I/dalvikvm(17043):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:529)
06-20 12:09:24.887: I/dalvikvm(17043):   at com.nostra13.universalimageloader.core.ImageDecoder.decode(ImageDecoder.java:82)
06-20 12:09:24.887: I/dalvikvm(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:270)
06-20 12:09:24.887: I/dalvikvm(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:244)
06-20 12:09:24.887: I/dalvikvm(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:149)
06-20 12:09:24.887: I/dalvikvm(17043):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
06-20 12:09:24.887: I/dalvikvm(17043):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
06-20 12:09:24.887: I/dalvikvm(17043):   at java.lang.Thread.run(Thread.java:856)
06-20 12:09:24.897: D/skia(17043): --- decoder->decode returned false
06-20 12:09:24.897: E/ImageLoader(17043): null
06-20 12:09:24.897: E/ImageLoader(17043): java.lang.OutOfMemoryError
06-20 12:09:24.897: E/ImageLoader(17043):   at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
06-20 12:09:24.897: E/ImageLoader(17043):   at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:529)
06-20 12:09:24.897: E/ImageLoader(17043):   at com.nostra13.universalimageloader.core.ImageDecoder.decode(ImageDecoder.java:82)
06-20 12:09:24.897: E/ImageLoader(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.decodeImage(LoadAndDisplayImageTask.java:270)
06-20 12:09:24.897: E/ImageLoader(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.tryLoadBitmap(LoadAndDisplayImageTask.java:244)
06-20 12:09:24.897: E/ImageLoader(17043):   at com.nostra13.universalimageloader.core.LoadAndDisplayImageTask.run(LoadAndDisplayImageTask.java:149)
06-20 12:09:24.897: E/ImageLoader(17043):   at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
06-20 12:09:24.897: E/ImageLoader(17043):   at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
06-20 12:09:24.897: E/ImageLoader(17043):   at java.lang.Thread.run(Thread.java:856)
}

我不知道如何解决这个问题。加载的图片大小是不确定的,可能会在500KB到1.5MB之间变化。

请查看以下链接,可能会有所帮助:https://dev59.com/emQn5IYBdhLWcg3wgnPg#16978285 - Raghunandan
3个回答

12

https://github.com/nostra13/Android-Universal-Image-Loader.

从上面的链接中,如果你的应用程序使用Universal Image Loader经常出现OutOfMemoryError错误,请尝试以下操作(全部或部分):

  1. 在配置文件中减少线程池大小(.threadPoolSize(...))。建议1-5个线程。

  2. 在显示选项中使用.bitmapConfig(Bitmap.Config.RGB_565)。使用RGB_565格式的位图比使用ARGB_8888格式的位图少消耗2倍的内存。

  3. 在配置中使用.memoryCache(new WeakMemoryCache()),或者在显示选项中完全禁用内存缓存(不要调用.cacheInMemory())。

  4. 在显示选项中使用.imageScaleType(ImageScaleType.IN_SAMPLE_INT)。或者尝试.imageScaleType(ImageScaleType.EXACTLY)

  5. 避免使用RoundedBitmapDisplayer。它在工作期间会创建一个具有ARGB_8888配置的新位图对象来进行显示。

示例:根据以上要点修改下面链接中的代码,以避免OOM

Caching images and displaying


好的,这就是文档所说的。如果图像太大,你可能会遇到内存泄漏的问题。因此,另一个选择是缩小图像。 - Raghunandan
请查看这个链接:https://dev59.com/WXDXa4cB1Zd3GeqP_l4f。看看Nostra本人的回答,也许会有所帮助。 - Raghunandan
@Raghunandan 你好,我已经使用 Picasso 和 Glide 加载图片了。但是它会出现内存问题。在我的应用程序中,我在主页上使用 RecyclerView 加载超过 200 张图片。你能给我一些建议,哪个库最适合避免内存不足问题吗? - Stephen
@Naruto 你可以尝试Facebook的Fresco。但Glide也非常不错。 - Raghunandan
@Raghunandan,我现在正在尝试使用通用图像加载器。之前我只尝试过Glide。我按照这个链接(https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en)来解决Glide的内存问题,但是无法解决。你知道如何使用Glide进行缩放和缓存以避免内存问题吗? - Stephen
显示剩余2条评论

4

已解决:

这不是UIL的问题,而是页面适配器的问题。片段中的位图没有被GC正确处理,并且有一些间接引用保留它们。显式释放位图解决了问题。

编辑:

这不是一个正常的UIL问题。我正在使用SupportFragment库,可能没有正确调整。对我来说,诀窍是手动释放每个不在屏幕上的位图,但问题应该从不同的角度考虑。这个应用程序使用了大量的WebViews,我认为它们的内存消耗非常愚蠢!添加带有高分辨率图像的UIL会使我的应用程序由于这些因素的组合而OOM。

这是一个有点经验主义的解决方案,但真的很有效。


13
你可以分享一下你的解决方案吗? - eshbeata
请提供您的解决方案! - AndyB

2

我有以下带有磁盘缓存的配置。我从未遇到过OOM问题。

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
            YourActivity.this).threadPoolSize(5)
            .threadPriority(Thread.MIN_PRIORITY + 3)
            .denyCacheImageMultipleSizesInMemory()
            // .memoryCache(new UsingFreqLimitedMemoryCache(2000000)) // You
            // can pass your own memory cache implementation
            .memoryCacheSize(1048576 * 10)
            // 1MB=1048576 *declare 20 or more size if images are more than
            // 200
            .discCache(new UnlimitedDiscCache(cacheDir))
            // You can pass your own disc cache implementation
            // .defaultDisplayImageOptions(DisplayImageOptions.createSimple())
            .build();

创建缓存目录:
File cacheDir = new File(this.getCacheDir(), "imgcachedir");
    if (!cacheDir.exists())
        cacheDir.mkdir();

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