Android - 释放分配的内存AnimationDrawable正在用完

Posted

技术标签:

【中文标题】Android - 释放分配的内存AnimationDrawable正在用完【英文标题】:Android - releasing allocated memory AnimationDrawable is using up 【发布时间】:2014-11-14 07:20:56 【问题描述】:

我有一个复杂的战斗系统,它有 1 个父 Activity,然后是几个子类,它们通过扩展 Battle 并将上下文传递给这些类来访问 BattleActivity 的静态变量。

这一切似乎工作正常,但是我在从内存中释放所有 AnimationDrawables 时遇到问题。一场战斗总共可以使用 24 个 DrawableAnimations。现在还可以,但是每次用户遇到一个新怪物时,就会有 4 个 AnimationDrawables 添加到内存中,这会慢慢地导致我的应用程序因 anb Out of Memory 异常而崩溃。

因此,我真的需要找到一种方法来释放我的战斗系统所占用的所有内存。目前,我在 Sony Z2 上进行测试,当用户进入战斗时,内存从 91mb 增加到 230mb。战斗结束后,我需要将此内存使用量恢复到 91mb。我添加了一些非常基本的代码 sn-p 让您了解应用程序当前的流程以及我正在尝试做什么来释放内存。

public class Battle extends Activity

     // I have several AnimationDrawables loaded into memory
     // These are then assigned the relevent animation to a button swicthing between these animations throughout my battle
    ImageButton btnChr1;
    AnimationDrawable cAnimHit1;


//This is the use of one of those AnimationDrawables
public class Battle_Chr_Anim extends Battle

    protected Context ctx;
    private ImageButton btnChr1;
    AnimationDrawable cAnimHit1;

    public Battle_Chr_Anim(Context c, ImageButton _btnChr1, AnimationDrawable _cAnimHit1)  
        this.ctx = c;
        this.btnChr1 = _btnChr1;
        this.cAnimHit1 = _cAnimHit1;
    

    // Bound the ImageButton
    int id = ctx.getResources().getIdentifier("idle", "drawable", ctx.getPackageName());
    img_chr1.setBackgroundResource(id);
    frameAnimation = (AnimationDrawable)img_chr1.getBackground();
    frameAnimation.start()

    // Loaded into memory ready so I can swicth them over quickly when user attacks
    int ca1 = ctx.getResources().getIdentifier("attack", "drawable", ctx.getPackageName());
    cAnimHit1 = (AnimationDrawable)chrHit1.getBackground();
    cAnimHit1.start();


public class Battle_Ended extends Battle

    protected Context ctx;

    public Battle_Ended(Context c)  
        this.ctx = c;
    

    //This is a dialog popup when the user completes the battle closing the battle activty
    void EndBattle()
    
        ImageButton btnSubmit = (ImageButton)dialog.findViewById(R.id.imgBtnSubmit);
        btnSubmit.setOnClickListener(new OnClickListener() 
            @Override
            public void onClick(View v) 
                Intent returnIntent = new Intent();
                setResult(RESULT_CANCELED, returnIntent);
                RecyleAllAnimations();
                dialog.dismiss();
                ((Activity) ctx).finish();
            
        );
    

    void RecyleAllAnimations()
    
        // I want all AnimationDrawables from memory here, I believe the below line removes the one currently in use, however I have no way of releasing the other animations sitting in memory.
        img_chr1.setBackgroundResource(android.R.color.transparent);
        System.gc();
    

【问题讨论】:

你真的有你传递应用程序上下文的静态变量吗?我认为他们会比你的可绘制对象更早地杀死你的应用程序 是的,这仅适用于我的战斗方面,因为我不希望我的所有代码都在同一个 Activity 中,而是简单地扩展这个类,以便我仍然可以访问 UI。因为我需要能够在加载 Activity 之前加载所有 AnimationDrawables,以便在用户进入战斗时动画可以流畅 【参考方案1】:

首先我认为你不能对AnimationDrawable 进行任何回收,除非你离开它们被声明的范围。不要中继System.gc();,让GC自动为你释放这些内存。

访问BattleActivity的静态变量

这是你的第一个错误。如果你使用静态变量,即使你离开你的活动,它们都在那里,你肯定会得到 OOM。

因此,我真的需要找到一种方法来释放我所有的记忆 我一退出战斗系统就开始了。

如果您将所有变量声明为非静态变量,那么当您离开它们定义的范围时,您将不会得到 OOM。虽然如果在活动运行期间创建 AnimationDrawable 没有任何界限,您可能会得到 OOM。

【讨论】:

我已经修改了我的代码,因此我不再使用静态 AnimationDrawable,但是即使在 Activity 被销毁并且用户返回到游戏地图页面之后,仍然存在释放内存的问题。还有其他想法吗? 你现在有什么问题? 好吧,简单地说,AnimatonDrawables 的内存没有被释放 我不确定,但我认为当您离开该活动时,gc 不会立即运行,我认为它仅在您需要更多内存且没有足够内存时运行,所以请四处看看它是否会做任何清洁与否。【参考方案2】:

使用静态 Drawable(s) 或 View(s) 会导致内存泄漏,因为 drawable 是有状态的。

您可以检查任何其他静态 Drawable(s) 或 View(s) 并删除它们或调用

drawable.setCallback(null);

你不能回收 Drawable 对象,调用 System.gc() 不是一个好习惯

您的应用似乎在某处出现内存泄漏,如果您尝试了上述方法并且内存仍以该速度扩展,请考虑使用memory analysis 来缩小问题范围。

【讨论】:

我不认为这是我遭受内存泄漏的事实,我认为这是可绘制使用的内存剪切量。我的意思是在一次加载时我有 30 个 AnimationDrawable 需要加载,每个包含大约 15 个图像,每个图像 256 像素 x 256 像素。因此,正如预期的那样,内存使用量猛增(根据设备加载也需要 2-4 秒)。这是我可以处理的,但是完成后我需要以某种方式释放该内存。每次遇到新怪物时,都会在内存中添加另外 5 个 AnimationDrawables 是的,但是如果您的 Activity 没有泄漏,则应根据需要释放内存,如果您在关闭 Activity 后手动调用 System.gc(),则这些 Drawable(s) 应从内存中清除,除非有泄漏。如果除了确保没有使用静态 Drawable 并且我提到的其他事情使它们在完成时指向 null 以避免可能的徘徊 我想我今晚必须研究一下,因为需要从所有 ImageViews 和 ImageButtons 中删除静态,然后才能正确测试它。检查内存泄漏和内存分析工具的背心方法是什么? 如果您的内存使用率一直在上升,这表明存在内存泄漏,请查看这些链接以了解如何查找泄漏,android-developers.blogspot.com/2011/03/… 和 developer.android.com/tools/debugging/debugging-memory.html 例如拥有一个静态 ImageView 会导致整个 Activity 被泄露(留在内存中),你应该摆脱所有这些静态 View(s) 和 Drawable(s)

以上是关于Android - 释放分配的内存AnimationDrawable正在用完的主要内容,如果未能解决你的问题,请参考以下文章

android 内存分哪些区

Android 性能优化之内存泄漏检测以及内存优化(上)

Android内存优化篇

Effective Android:app优化 ------ 内存管理内存泄漏冷启动

Android系统内存管理

Android ART虚拟机 Space类体系