Android内存泄漏 - 无法正确释放位图,内存不足错误 - 位图大小超过VM预算[Mono Android]

时间:2012-12-10 15:18:42

标签: android bitmap mono android-listview out-of-memory

我似乎无法弄清楚为什么我的活动内存不足。

当我加载活动时,我有一堆图像被加载到自定义列表视图适配器中。当我开始活动时,屏幕加载正常。但是当我改变方向或返回并再次启动时,活动会生成内存不足异常。

以下是我的活动:

Fish Species Activity that Crashes

以下是我的活动代码:

    [Activity(Label = "FishinTales: Fish Species")]
public class Activity_View_FishSpecies : Activity
{
    #region Components
    private Model n_model;
    private ListView n_fishSpeciesListView;
    #endregion

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Get Application Global Model
        this.n_model = ((MyApp) this.ApplicationContext).FishingData;

        // Set our view from the "View_FishSpecies" layout resource
        SetContentView(Resource.Layout.View_FishSpecies);

        this.n_fishSpeciesListView = FindViewById<ListView> (Resource.Id.xml_fishSpeciesListView);
        this.n_fishSpeciesListView.Adapter = new FishSpeciesListAdapter (this.ApplicationContext, this.n_model.SpecieManager.Species);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        this.unbindDrawables(FindViewById(Resource.Id.xml_root));
        this.n_fishSpeciesListView.Adapter = null;
        this.n_fishSpeciesListView = null;
    }

    private void unbindDrawables(View view) {
        if (view.Background != null) {
            view.Background.SetCallback(null);
        }
        if (view.GetType() == typeof(ViewGroup)) {
            for (int i = 0; i < ((ViewGroup) view).ChildCount; i++) {
                unbindDrawables(((ViewGroup) view).GetChildAt(i));
            }
            ((ViewGroup) view).RemoveAllViews();
        }
    }
}

public class FishSpeciesListAdapter : BaseAdapter
{
    Context n_context;
    List<AppCode.Specie> n_specieData;
    List<Bitmap> n_bitmapCache;

    public FishSpeciesListAdapter (Context context, List<AppCode.Specie> specieData)
    {
        this.n_context = context;
        this.n_specieData = specieData;
        this.n_bitmapCache = new List<Bitmap>();
        this.LoadBitmapsIntoCache();
    }

    private void LoadBitmapsIntoCache()
    {
        foreach(AppCode.Specie specie in this.n_specieData)
        {
            if (specie.RelatedMedia.AttachedPhotos.Count < 1)
            {
                this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon)); 
            }
            else
            {
                this.n_bitmapCache.Add(BitmapFactory.DecodeByteArray(specie.RelatedMedia.AttachedPhotos[0], 0, specie.RelatedMedia.AttachedPhotos[0].Length));  
            }
        }
    }

    public override int Count {
        get { return this.n_specieData.Count; }
    }

    public override Java.Lang.Object GetItem (int position)
    {
        return null;
    }

    public override long GetItemId (int position)
    {
        return 0;
    }

    // create a new ImageView for each item referenced by the Adapter
    public override View GetView (int position, View convertView, ViewGroup parent)
    {
        if(convertView==null){

            LayoutInflater li = LayoutInflater.FromContext(parent.Context);
            convertView = li.Inflate(Resource.Layout.Adapter_FishSpeciesIcon, null);
        }

        ImageView iconImage = (ImageView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesIconImage);
        TextView nameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesNameText);
        TextView scientificNameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesScientificNameText);

        nameText.Text = this.n_specieData[position].Name;
        scientificNameText.Text = this.n_specieData[position].ScientificName;
        iconImage.SetImageBitmap(this.n_bitmapCache[position]); 

        return convertView;
    }
}

这是我生成OOM错误之前所有进程的日志。

    Loading Defaults - Successfully Loaded Defaults
Grow heap (frag case) to 6.474MB for 314670-byte allocation
Clamp target GC heap from 32.512MB to 32.000MB
796824-byte external allocation too large for this process.
VM won't let us allocate 796824 bytes
Clamp target GC heap from 33.447MB to 32.000MB
--- decoder->decode returned false
UNHANDLED EXCEPTION: Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>

  --- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
    at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
    at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:625)
    at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:638)
    at fishintales.Activity_View_FishSpecies.n_onCreate(Native Method)
    at fishintales.Activity_View_FishSpecies.onCreate(Activity_View_FishSpecies.java:29)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1780)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1837)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3242)
    at android.app.ActivityThread.access$1600(ActivityThread.java:132)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1037)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:143)
    at android.app.ActivityThread.main(ActivityThread.java:4196)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)

Unhandled Exception:
Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>

  --- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
    at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
    at android.gra

当我最初查看活动时,一切都很好。当我离开活动并多次回到它时,它最终会因上述错误而崩溃。这导致我推测错误来自内存泄漏,其中位图未正确回收。那么有没有关于如何解释这些位图的例子呢?当您的位图位于Custom ListView Adapter类中时,很难找到有关此主题的信息。当我在设置它之后放入Bitmap.recycle时,我收到另一个错误,指出ListView正在尝试访问回收的项目。那么我应该如何/何时根据上面的代码进行回收。

1 个答案:

答案 0 :(得分:1)

我想知道您使用的是哪个版本的Android。如果是Jelly Bean(Android 4.1.1),请删除此行代码

this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon)); 

并查看是否有内存泄漏。

我的应用程序在Android 4.1.1更新后也开始出现内存泄漏,我发现问题在

setBackgroundResource(id);

我尝试将其更改为

setBackground(context.getResources().getDrawable(id));

但仍然是内存泄漏。我想确认是否是我的代码中的错误或Jelly Bean中的错误,如果我们尝试从Resources创建drawables或bitmaps,则会导致内存泄漏。 抱歉没有回答你的问题,但我们至少可以知道错误的原因并提出Android团队的问题。

<强>更新 我在link

中找到了解决方案

请对从资源的drawable文件夹创建的位图使用setBackgroundDrawable(null)。