Как заставить сбой от утечки памяти на Android? - PullRequest
0 голосов
/ 16 октября 2018

Итак, я часто слышу, что «удержание статической активности или представления, особенно внутри 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 МБ.

Как я могу заставить приложение аварийно завершить работу?(Пожалуйста, не спрашивайте, почему я хочу заставить приложение аварийно завершить работу, я провожу некоторое ограничение)

1 Ответ

0 голосов
/ 16 октября 2018

Я часто слышу, что «удержание статической активности или представления, особенно внутри 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 и т. Д. Однако, чтобы продемонстрировать эту утечку, вам нужно запустить приложение, затем нажать НАЗАД и увидеть, что ваша уничтоженная активность несборщиком мусора.Либо вам нужно запустить приложение, повернуть экран (или изменить конфигурацию любого другого типа) и увидеть, что теперь у вас есть два экземпляра активности: разрушенный и с утечкой и текущий.Если вы просто запускаете приложение и ничего не делаете, у вас нет утечки активности - хотя у вас есть собственная статическая ссылка на нее, то же самое происходит и с Android, потому что активность находится на переднем плане, и пользователь может ее видеть.

Утечка сама по себе не вызывает сбой.Это просто означает, что вы связываете кучу пространства, которое нельзя использовать для других целей.В конце концов, вы получите OutOfMemoryError на некоторое распределение.Если все, что вы хотите сделать, это аварийно завершить работу с OutOfMemoryError, попробуйте выделить несколько крупных byte[] (скажем, 1 ГБ).

Если вы специально хотите протестировать OutOfMemoryError, вызванный утечкой активности, вы бынеобходимо:

  • Чтобы действие выделило значительный объем пространства кучи (например, 1 МБ byte[]),

  • Сделайте что-то вродеваш список sHolder и

  • Поверните экран сильно или иным образом поставьте себя в ситуацию, когда множество экземпляров действия будут созданы и уничтожены, но не собраны мусоромЛюбезно предоставлено sHolder

...