如何从Android上的内存泄漏强制崩溃?

时间:2018-10-15 23:12:55

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

因此,我经常听到“坚持静态活动或视图,尤其是长时间运行的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的垃圾收集正在发生。

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

1 个答案:

答案 0 :(得分:5)

  

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

这是一个简化的解释。

  

但是,我一直无法在Android模拟器中实际证明这一点。

我怀疑此代码未运行。在经过数百次循环后,您应该崩溃,因为可以排队的AsyncTasks数量是有限制的,并且该限制与内存消耗无关。

忽略百万AsyncTasks和百万ImageViews,您将通过sHolder泄漏活动,就像在此示例中,我如何通过持有{{1 }}从其布局中引用static

Button

您可以使用LeakCanary,Android Studio的堆分析器等演示泄漏发生。但是,要演示该泄漏,您需要运行应用程序,然后按BACK,然后查看未破坏的活动没有被垃圾收集。或者,您需要运行该应用程序,旋转屏幕(或进行任何其他类型的配置更改),然后查看您现在有两个活动实例,一个被破坏并泄漏的活动实例,另一个是当前活动实例。如果您只运行该应用程序却不执行任何操作,则您尚未泄漏该活动-尽管您拥有自己的静态引用,但Android也是如此,因为该活动位于前台并且用户可以看到它。

泄漏本身并不会导致崩溃。这仅表示您正在占用无法用于其他用途的堆空间。最终,您将获得/*** 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); } } 的分配。如果您要做的只是使OutOfMemoryError崩溃,请尝试分配一些庞大的OutOfMemoryError(例如1GB)。

如果您特别想测试由泄漏的活动触发的byte[],则需要:

  • 有一个活动分配大量的堆空间(例如1MB OutOfMemoryError),

  • 执行类似您的byte[]列表的操作,然后

  • 大量旋转屏幕,否则,您的sHolder

    可能会创建和销毁许多活动实例,但不会进行垃圾回收,