安卓 - 释放已分配的内存,AnimationDrawable 正在消耗内存

9
我有一个复杂的战斗系统,它有一个父活动和几个子类,这些子类通过扩展Battle并将上下文传递给这些类来访问BattleActivity的静态变量。
这一切似乎都很好,但是我在释放所有AnimationDrawables的内存方面遇到了问题。在一场战斗中可能会使用24个DrawableAnimations。目前还可以,但每当用户遇到新怪物时,就会向内存中添加4个AnimationDrawables,这将慢慢地导致我的应用程序因为内存不足而崩溃。
因此,我真的需要找到一种方法,尽快释放战斗系统占用的所有内存。目前,我正在Sony Z2上进行测试,当用户进入战斗时,内存从91mb增加到230mb。当战斗完成后,我需要将内存使用量降回到91mb。我已经添加了一些非常基本的代码片段,以便让您了解应用程序当前的流程以及我试图做什么来释放内存。
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();
    }
}

你真的有静态变量传递应用程序上下文吗?我认为它们会比你的可绘制对象更早地导致应用程序崩溃。 - MineConsulting SRL
是的,这只是为了我的战斗部分,因为我不想把所有的代码都放在同一个Activity中,而是扩展这个类,以便我仍然可以访问UI。因为我需要能够在加载Activity之前加载所有的AnimationDrawables,以便当用户进入战斗时动画可以流畅运行。 - SingleWave Games
2个回答

0

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

它访问了BattleActivity的静态变量

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

因此,我真的需要找到一种方法,在我退出时立即释放战斗系统占用的所有内存。

如果你将所有变量声明为非静态变量,那么当你离开它们定义的范围时,你就不会遇到OOM。尽管在活动运行期间创建没有任何边界的AnimationDrawable可能会导致OOM。


我已经修改了我的代码,以便不再使用静态AnimationDrawable,但是即使活动结束并且用户返回游戏地图页面,仍然存在释放内存的问题。还有其他想法吗? - SingleWave Games
你现在有什么问题? - mmlooloo
简单来说,AnimationDrawables的内存没有被释放。 - SingleWave Games
我不确定,但我认为当您离开该活动时,垃圾回收程序不会立即运行,我认为它只有在需要更多内存且没有足够内存时才会运行,因此请尝试一下,看看它是否会进行任何清理。 - mmlooloo

0

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

你可以检查是否有其他静态的Drawable或View并将其清除,或者调用

drawable.setCallback(null);

你不能重复使用Drawable对象,而且调用System.gc()也不是一个好的做法。

看起来你的应用程序在某个地方存在内存泄漏问题,如果你尝试了上述方法,但内存仍然以那种速度增长,那么考虑进行内存分析以缩小问题范围。


我认为问题不在于我遭受了内存泄漏,而是Drawable使用的内存量太大了。我的意思是,在一次加载中,我需要加载30个AnimationDrawable,每个动画由大约15张256px x 256px的图片组成。因此,预期的内存使用量会急剧增加(根据设备不同,还需要2-4秒才能加载完成)。这个我可以处理,但是一旦完成后,我需要想办法释放那些内存。因为每当遇到新的怪物时,就会再添加5个AnimationDrawables到内存中。 - SingleWave Games
没错,但如果你的 Activity 没有泄露,内存应该会在需要时释放。此外,如果在关闭 Activity 后手动调用了 System.gc(),那么除非有泄漏,否则这些 Drawable 应该会从内存中清除。如果除了确保不使用静态 Drawable 之外,还将它们在完成后指向 null,以避免可能出现的悬空引用呢? - Mostafa Gazar
我想今晚必须研究一下,因为需要从所有的ImageViews和ImageButtons中去除静态内容,然后才能进行适当的测试。检查内存泄漏和内存分析工具的最佳方法是什么? - SingleWave Games
拥有一个静态的ImageView,例如,会导致整个Activity泄漏(停留在内存中),你应该摆脱所有这些静态View和Drawable。 - Mostafa Gazar
是的,我现在正在处理这个问题,这是否适用于所有视图,包括像 TextView 这样的控件? - SingleWave Games
显示剩余2条评论

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