防止Android中的内存泄漏 [英] Prevent memory leak in Android

查看:69
本文介绍了防止Android中的内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Android上出现内存泄漏问题.
我确实有一个简单的应用程序,带有一个相对的图片作为背景,并且在我改变方向之前效果很好.

I'm having some troubles with memory leaks on Android.
I do have a simple application with a relatively picture as background and it works fine, until I change the orientation.

以下是显示内存泄漏(随时间分配的内存)的图表.每个峰值对应一个方向更改,每个峰值为+ 20M的已分配内存

The following is a graph showing the memory leak (allocated memory over time). Every spike corresponds to an orientation change, and every spike is +20M of allocated memory

在约30秒内,应用程序崩溃并出现明显的"OutOfMemory"错误:

At ~ 30 seconds the app crashes with an obvious "OutOfMemory" error:

Throwing OutOfMemoryError未能分配17469452字节分配,其中包含804912可用字节和786KB,直到OOM为止."

Throwing OutOfMemoryError "Failed to allocate a 17469452 byte allocation with 804912 free bytes and 786KB until OOM"`

布局只是一个简单的RelativeLayout,以jpeg图像为背景 大小〜430k

The layout is just a simple RelativeLayout with a jpeg image as background sized ~ 430k

我确实也实现了onDestroy()反内存泄漏解决方案(如建议此处):

I do have implemented also an onDestroy() anti-memory leak solution (as suggested here):

@Override
protected void onDestroy()
{
    unbindDrawables(view);
    view = null;
    System.gc();
    super.onDestroy();
}

private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

但是它真的没有任何改变.

But it really don't change anything.

有什么我可以解决的问题吗? 我确实需要图像大一点,因为运行该应用程序的设备的屏幕很大.

Is there anything I can do to solve the issue? I do need the image to be that big because the device running the app has a big screen.

-编辑-
根据要求添加onCreate()代码, 请注意,即使不调用initMainView(),甚至是空的onCreate()(仅具有super),该问题仍然存在,即使内存泄漏较差(仅0.8M),但仍然存在.
如果可以的话,我正在Pixel C上运行Android 6.0.1.

-- Edit --
Adding onCreate() code as requested, please do note that the problem is present even without calling initMainView() and even by having an empty onCreate() (with super only), even tough the memory leak is inferior (only 0.8M) but still present.
I'm running Android 6.0.1 on a Pixel C, if that might help.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    System.gc();
    w = getWindow();
    w.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    dpm = (DevicePolicyManager) this.getSystemService(Context.DEVICE_POLICY_SERVICE);
    deviceAdmin = new ComponentName(this, AdmRcvr.class);

    if(!dpm.isDeviceOwnerApp(getPackageName())) {
        setContentView(R.layout.deviceownertutorial);
        final TextView tvTutorial = (TextView) w.findViewById(R.id.tutorialtv);
        tvTutorial.setText(Html.fromHtml(getString(R.string.deviceownertutorial)));

        final TextView tvDeviceOwnerError = (TextView) w.findViewById(R.id.tverrordeviceadmin);

        Button checkDeviceAdmin = (Button) w.findViewById(R.id.cdevadmin);
        checkDeviceAdmin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (dpm.isDeviceOwnerApp(getPackageName())) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            setContentView(R.layout.startview);
                            initMainView();
                        }
                    });
                } else {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            tvDeviceOwnerError.setText("App is not the device admin");
                            tvDeviceOwnerError.setVisibility(View.VISIBLE);
                        }
                    });
                }
            }
        });
    }
    else
    {
        setContentView(R.layout.startview);
        initMainView();
    }
}


public void initMainView(){
    // We're device owners!
    View mDecorView = w.getDecorView();
    mDecorView.setSystemUiVisibility(
            View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
    mDecorView = null;
    view = findViewById(R.id.sv_relativelayout);
    initReader();
    initBitmapCache();
    enableTimer();
    currentStep = 1;
}

-编辑2 ---

在以下图像中,您可以看到两种情况下的内存分配:使用我所有的应用程序垃圾(如430kB图像)[a],不使用(干净的onCreate())[b].
请注意,如上所述,在两种情况下都仍然存在内存泄漏,即使这不是那么大(但确实有!).

In the following images you could see the memory allocation in two situation: with all my app garbage (like the 430kB image) [a] and without (a clean onCreate()) [b].
Please do note that the memory leak is still present in both situation, as stated above, even tough it isn't that big (but there is!).

内存泄漏,案例[a]

Memory leak, case [a]

内存泄漏,案例[b]

Memory leak, case [b]

该应用程序是根据SDK v.23和buildToolsVersion 23.0.2编译的. 依赖关系如下:

The app is compiled against SDK v.23 and with buildToolsVersion 23.0.2. The dependencies are the following:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
}

应用程序/库如下:

libs
└── acssmc-1.1.2.jar  

-编辑3 ---
在使用新创建的应用程序进行测试时,应按需要对内存进行管理,您可以在我的 GitHub存储库中查看示例

--- EDIT 3 ---
When testing with a newly created application the memory is managed as it should, you could see an example on my GitHub repo

推荐答案

我已经设法解决了这个问题.
这全是因为该死的计时器在每次屏幕方向更改时都设置了一个滴答事件.
要解决此问题,我只是将计时器绑定到一个变量,并在onSaveInstance()

I've managed to solve the problem.
It was all because of a damn timer which was setting a tick event on every screen orientation change.
To fix the issue I simply binded the timer to a variable, and called timer.cancel() in onSaveInstance()

现在我的内存泄漏消失了(如下所示):

Now my memory leaks are gone (as shown below):

这篇关于防止Android中的内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆