android如何避免这种内存不足错误

android如何避免这种内存不足错误,android,out-of-memory,drawable,Android,Out Of Memory,Drawable,我有很多图像,比如500个,分布在20个左右的片段上,这些图像都很小,负载也很好,但是我让用户从3种不同的图像中进行选择,现在如果用户更改图像,我会得到一个OOM错误,因此,我认为这就是我处理图像的方式,我认为我需要首先回收旧图像,但我对如何做到这一点没有信心,有人能帮忙吗 下面是我如何填充适配器的我刚刚添加了两项来简化事情 private void prepareCardData(){ CardWriter cardWriter = new CardWriter(getRes

我有很多图像,比如500个,分布在20个左右的片段上,这些图像都很小,负载也很好,但是我让用户从3种不同的图像中进行选择,现在如果用户更改图像,我会得到一个OOM错误,因此,我认为这就是我处理图像的方式,我认为我需要首先回收旧图像,但我对如何做到这一点没有信心,有人能帮忙吗

下面是我如何填充适配器的我刚刚添加了两项来简化事情

    private void prepareCardData(){

    CardWriter cardWriter = new CardWriter(getResources().getDrawable(R.drawable.dog),"DOG","dog ");
    cardMakerList.add(cardWriter);

    cardWriter = new CardWriter(getResources().getDrawable(R.drawable.cat_ic),"CAT","cat ");
    cardMakerList.add(cardWriter);

    cardAdapter.notifyDataSetChanged();
}
这就是我真正等待共享偏好改变并调用方法的地方

private SharedPreferences.OnSharedPreferenceChangeListener listener = new     
SharedPreferences.OnSharedPreferenceChangeListener() {
    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if(key.equals("ICONS SELECTED")){
            cardsChoice.setIcons(getActivity());
            cardsToSet();
            System.out.println("OneFrag pref listener");
        }
    }
};
public void cardsToSet(){
    if (cardsChoice.bool_fragTwo == false) {
        if (cardsChoice.group == 1) {
            cardMakerList.clear();
            prepareCardData();
            cardsChoice.bool_fragTwo = true;
        }
        if (cardsChoice.group == 2) {
            cardMakerList.clear();
            prepareSimpleCardData();
            cardsChoice.bool_fragTwo = true;
        }
        if (cardsChoice.group == 3) {
            cardMakerList.clear();
            preparePhotoCardData();
            cardsChoice.bool_fragTwo = true;
        }
    }
}
如前所述,我认为我需要在自己的线程中运行它,并清除不再需要的图像,但我认为还有更多的内容,有人可以帮助吗

这是堆栈跟踪

06-12 17:39:47.878 13189-13219/ss.sealstudios.com.socialstories E/Surface: getSlotFromBufferLocked: unknown buffer: 0x8a12fe70
06-12 17:39:47.985 13189-13189/ss.sealstudios.com.socialstories I/System.out: OneFrag pref listener
06-12 17:39:47.987 13189-13189/ss.sealstudios.com.socialstories I/System.out: OneFrag pref listener
06-12 17:39:48.233 13189-13199/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 265MB to 256MB
06-12 17:39:48.380 13189-13189/ss.sealstudios.com.socialstories I/System.out: OneFrag pref listener
06-12 17:39:48.410 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.410 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.416 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc sticky concurrent mark sweep GC freed 108(4KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 254MB/256MB, paused 303us total 5.710ms
06-12 17:39:48.417 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.433 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 283MB to 256MB
06-12 17:39:48.433 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc partial concurrent mark sweep GC freed 5841(393KB) AllocSpace objects, 2(3MB) LOS objects, 1% free, 251MB/256MB, paused 793us total 15.361ms
06-12 17:39:48.493 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.494 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.502 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc sticky concurrent mark sweep GC freed 17(688B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 545us total 7.748ms
06-12 17:39:48.503 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.526 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.526 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc partial concurrent mark sweep GC freed 23(944B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 494us total 22.482ms
06-12 17:39:48.527 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.567 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.567 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc concurrent mark sweep GC freed 9(12KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 499us total 38.887ms
06-12 17:39:48.568 13189-13189/ss.sealstudios.com.socialstories I/art: Forcing collection of SoftReferences for 2025KB allocation
06-12 17:39:48.568 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.597 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.597 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc concurrent mark sweep GC freed 11(344B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 501us total 28.481ms
06-12 17:39:48.601 13189-13189/ss.sealstudios.com.socialstories W/art: Throwing OutOfMemoryError "Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM"
06-12 17:39:48.603 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.603 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.610 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc sticky concurrent mark sweep GC freed 3(448B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 484us total 6.214ms
06-12 17:39:48.611 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.643 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.643 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc partial concurrent mark sweep GC freed 6(192B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 1.131ms total 31.104ms
06-12 17:39:48.644 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.673 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.673 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 631us total 29.306ms
06-12 17:39:48.674 13189-13189/ss.sealstudios.com.socialstories I/art: Forcing collection of SoftReferences for 2025KB allocation
06-12 17:39:48.674 13189-13189/ss.sealstudios.com.socialstories I/art: Starting a blocking GC Alloc
06-12 17:39:48.704 13189-13189/ss.sealstudios.com.socialstories I/art: Clamp target GC heap from 287MB to 256MB
06-12 17:39:48.704 13189-13189/ss.sealstudios.com.socialstories I/art: Alloc concurrent mark sweep GC freed 3(96B) AllocSpace objects, 0(0B) LOS objects, 0% free, 255MB/256MB, paused 306us total 29.616ms
06-12 17:39:48.705 13189-13189/ss.sealstudios.com.socialstories W/art: Throwing OutOfMemoryError "Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM"
06-12 17:39:48.709 13189-13189/ss.sealstudios.com.socialstories D/skia: --- allocation failed for scaled bitmap
06-12 17:39:48.709 13189-13189/ss.sealstudios.com.socialstories D/AndroidRuntime: Shutting down VM
06-12 17:39:48.724 13189-13189/ss.sealstudios.com.socialstories E/AndroidRuntime: FATAL EXCEPTION: main
                                                                                  Process: ss.sealstudios.com.socialstories, PID: 13189
                                                                                  java.lang.OutOfMemoryError: Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM
                                                                                      at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
                                                                                      at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
                                                                                      at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609)
                                                                                      at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444)
                                                                                      at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080)
                                                                                      at android.content.res.Resources.loadDrawableForCookie(Resources.java:2738)
                                                                                      at android.content.res.Resources.loadDrawable(Resources.java:2643)
                                                                                      at android.content.res.Resources.getDrawable(Resources.java:833)
                                                                                      at android.content.res.Resources.getDrawable(Resources.java:786)
                                                                                      at ss.sealstudios.com.socialstories.TwoFragment.prepareCardData(TwoFragment.java:280)
                                                                                      at ss.sealstudios.com.socialstories.TwoFragment.cardsToSet(TwoFragment.java:245)
                                                                                      at ss.sealstudios.com.socialstories.TwoFragment$2.onSharedPreferenceChanged(TwoFragment.java:236)
                                                                                      at android.app.SharedPreferencesImpl$EditorImpl.notifyListeners(SharedPreferencesImpl.java:479)
                                                                                      at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:387)
                                                                                      at android.preference.Preference.tryCommit(Preference.java:1419)
                                                                                      at android.preference.Preference.persistString(Preference.java:1452)
                                                                                      at android.preference.ListPreference.setValue(ListPreference.java:148)
                                                                                      at android.preference.ListPreference.onDialogClosed(ListPreference.java:283)
                                                                                      at android.preference.DialogPreference.onDismiss(DialogPreference.java:395)
                                                                                      at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1328)
                                                                                      at android.os.Handler.dispatchMessage(Handler.java:102)
                                                                                      at android.os.Looper.loop(Looper.java:148)
                                                                                      at android.app.ActivityThread.main(ActivityThread.java:5527)
                                                                                      at java.lang.reflect.Method.invoke(Native Method)
                                                                                      at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:730)
                                                                                      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:620)

如果图像视图包含位图可绘制的实例

Drawable drawable = imageView.getDrawable();
if(drawable!=null && BitmapDrawable.class.isAssignableFrom(drawable.getClass())) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
    Bitmap bitmap = bitmapDrawable.getBitmap();
    if(bitmap != null && !bitmap.isRecycled()) bitmap.recycle();
}
但是

如果从不大(以兆字节为单位)的可绘制文件夹加载位图,则不应真正遇到问题

如果加载资源,则需要检查它们是否适合显示它们的位置,例如,如果显示图像的区域大小为64x64,则没有必要将ImageView设置为1024 x 1024大小的图像

OOM通常是由加载未知大小的图像或只是如上所述的图像大小错误引起的,频繁交换ImageView通常不会给您带来最佳大小图像的问题

您应该阅读一些有关位图的指南:

对于您的情况:

这是堆栈跟踪的基本片段:

FATAL EXCEPTION: main Process: ss.sealstudios.com.socialstories, PID: 13189 
java.lang.OutOfMemoryError: Failed to allocate a 2073612 byte allocation with 559872 free bytes and 546KB until OOM 
at dalvik.system.VMRuntime.newNonMovableArray(Native Method) 
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609) 
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444) 
at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:1080) 
at android.content.res.Resources.loadDrawableForCookie(Resources.java:2738) 
at android.content.res.Resources.loadDrawable(Resources.java:2643) 
at android.content.res.Resources.getDrawable(Resources.java:833) at android.content.res.Resources.getDrawable(Resources.java:786) 
at ss.sealstudios.com.socialstories.TwoFragment.prepareCardData(TwoFragment.java:280) 
无法分配2073612字节的分配,其中有559872个可用字节和546KB,直到OOM

因此,一般而言:

  • 在方法TwoFragment.prepareCardData(TwoFragment.java:280)中 在调用Resources.getDrawable(..)之前,您应该获取图像视图并回收位图
  • 在fragment/activity中,您还应该在onDestroy()方法中循环使用位图
如果没有更多的代码,我无法确定是某个循环导致OOM,还是您没有释放资源

您也可以在将资源设置为“图像视图”之前执行此操作(缩放图像):

小心

不要使用已经回收的图像

您将得到异常:Canvas:尝试使用回收的位图

bitmap.recycle()对于android>2.3.3来说并不是严格要求的。如果您仍然希望强制回收此内存,则必须找到一种方法来检查位图何时确实不再需要(即,Canvas有机会完成其绘图操作)

问题是,您可能大量使用位图(分配的速度可能大于位图回收的速度),然后您可能希望尽快回收未使用的位图。使用完位图后,应调用recycle()

始终记住,当位图显示在屏幕上时,不要尝试循环使用它。

因此:

  • 抓取对旧位图的引用
  • 设置新的
  • 使视图无效
  • 检查旧位图是否尚未回收
  • 回收旧的
  • 您还可以调用System.gc()^
^向VM指示运行垃圾回收器的最佳时机。请注意,这只是一个提示。不能保证垃圾收集器将实际运行

调用ImageView.setImageBitmap()或相似性将不会回收位图使用的内存

为什么??因为当你特别关注ImageView方法的实现时:

private void updateDrawable(Drawable d) {
    if (d != mRecycleableBitmapDrawable && mRecycleableBitmapDrawable != null) {
        mRecycleableBitmapDrawable.setBitmap(null);
    }
...


public void setImageResource(@DrawableRes int resId) {
    // The resource configuration may have changed, so we should always
    // try to load the resource even if the resId hasn't changed.
    final int oldWidth = mDrawableWidth;
    final int oldHeight = mDrawableHeight;

    updateDrawable(null);
....

public void setImageBitmap(Bitmap bm) {
    // Hacky fix to force setImageDrawable to do a full setImageDrawable
    // instead of doing an object reference comparison
    mDrawable = null;
    if (mRecycleableBitmapDrawable == null) {
        mRecycleableBitmapDrawable = new ImageViewBitmapDrawable(
                mContext.getResources(), bm);
    } else {
        mRecycleableBitmapDrawable.setBitmap(bm);
    }
    setImageDrawable(mRecycleableBitmapDrawable);
}
另见:


你能对oom ex进行堆栈后跟踪吗?我添加了堆栈跟踪,根据文件管理器的说法,我的平均图像大小约为60kb,没有图像大于200x200,尽管图像视图通常比这小得多,所以我肯定会接受你的观点,您是否建议在异步任务中执行此操作,或者这是一种过度的操作,可能是冗余的操作?我回收的一些映像正在尝试再次访问,并向我提供了您需要的错误信息predicted@MartinSeal-查看我的编辑(首先交换位图,使视图无效,然后回收旧位图-但在设置新位图之前,请保持对位图的引用!!!)如果你对答案投赞成票也很好