【问题标题】:How to force a crash from memory leak on Android?如何在 Android 上强制因内存泄漏而崩溃?
【发布时间】:2018-10-15 23:12:55
【问题描述】:

所以,我经常听到“坚持静态活动或视图,尤其是在长时间运行的 AsyncTask 中会导致内存泄漏并使您的应用程序崩溃”。

但是,我未能在 Android 模拟器中实际证明这一点。

我做错了什么?

public class MainActivity extends AppCompatActivity {

static TextView label;
static List<Activity> sHolder = new ArrayList<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ViewGroup vg = findViewById(R.id.blah);
    for (int i=0; i<1000000; i++) {
        ImageView im = new ImageView(this);
        im.setImageDrawable(getApplicationContext().getDrawable(R.drawable.kitten_original));
        vg.addView(im);

        new MyTask(this).execute();
    }

    sHolder.add(this);
}

@Override
protected void onStart() {
    super.onStart();
}

@Override
protected void onStop() {
    super.onStop();
}

@Override
protected void onDestroy() {
    super.onDestroy();
}

class MyTask extends AsyncTask<Void, Void, Void> {

    Activity activity;
    public MyTask(Activity activity) {
        this.activity = activity;
    }
    @Override
    protected Void doInBackground(Void... voids) {
        try {
            Thread.sleep(10000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
}

不是每次崩溃,我的电脑只是开始有点滞后,并且一直看到 100 MB 的垃圾收集发生。

我如何才能真正强制应用程序崩溃? (请不要问我为什么要强制应用崩溃,我正在做一些极限测试)

【问题讨论】:

  • 您的活动基本上是空的,因此当您泄漏它时,需要多次重复才能导致崩溃。如果它有一些内容/引用其他异步任务/布局,它会更快崩溃。

标签: android android-activity memory-management android-memory


【解决方案1】:

我经常听到“坚持静态活动或视图,尤其是在长时间运行的 AsyncTask 中会导致内存泄漏并使您的应用程序崩溃”。

这是一个简化的解释。

但是,我未能在 Android 模拟器中实际证明这一点。

我怀疑这段代码没有运行。您应该在循环通过几百次后崩溃,因为您可以拥有多少排队的AsyncTasks 是有限制的,并且该限制与内存消耗无关。

忽略百万 AsyncTasks 和百万 ImageViews,您正在通过 sHolder 泄漏活动,就像在此示例中我通过持有 static 引用来泄漏活动一样 Button从它的布局来看:

/***
 Copyright (c) 2015 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain    a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS,    WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 Covered in detail in the book _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.button;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;

public class ButtonDemoActivity extends Activity {
  private static Button pleaseDoNotDoThis;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    pleaseDoNotDoThis=(Button)findViewById(R.id.button1);
  }
}

您可以使用 LeakCanary、Android Studio 的堆分析器等来证明发生了泄漏。但是,要证明该泄漏,您需要运行应用程序,然后按 BACK,并查看您销毁的 Activity 没有被垃圾回收。或者,您需要运行应用程序,旋转屏幕(或进行任何其他类型的配置更改),然后看到您现在有两个活动实例,一个是被破坏和泄漏的,一个是当前的。如果您只是运行应用程序并且什么都不做,那么您并没有泄露 Activity — 虽然您有自己的静态引用,Android 也是如此,因为 Activity 位于前台并且用户可以看到它。

泄漏本身不会导致崩溃。这只是意味着您正在占用不能用于其他事情的堆空间。最终,您将在某些分配上获得OutOfMemoryError。如果您只想使用OutOfMemoryError 崩溃,请尝试分配一些大量的byte[](例如1GB)。

如果您特别想测试由泄露活动触发的OutOfMemoryError,您需要:

  • 让活动分配大量堆空间(例如,1MB byte[]),

  • 像你的sHolder 列表那样做一些事情,然后

  • 频繁旋转屏幕,或以其他方式将自己置于将创建和销毁大量 Activity 实例但不会被垃圾收集的情况,感谢您的 sHolder

    李>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-27
    • 1970-01-01
    • 2012-02-22
    • 2020-09-07
    • 1970-01-01
    • 2017-07-31
    • 2018-04-04
    • 2013-02-04
    相关资源
    最近更新 更多