Объекты темы, а не сбор мусора после завершения

Я заметил, что в моем приложении происходит утечка памяти. Это можно увидеть в DDMS, и мне удалось получить OutOfMemoryError.

Я нашел источник утечки. В одном из действий поток работает в фоновом режиме. Этот поток остановлен в onDestroy() . Он заканчивается, как это видно в DDMS.

Теперь, если поток запущен, происходит утечка: Activity не является мусором, собранным после его уничтожения, потому что на него ссылается поток. Если нить не запускается вообще, все в порядке.

Вот простой пример, демонстрирующий это:

 public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } volatile boolean finished = false; byte[] memoryEater = new byte[4 * 1024 * 1024]; Thread thread = new Thread(new Runnable() { @Override public void run() { while (!finished) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } Log.d(getClass().getName(), "Thread finished"); } }); @Override protected void onDestroy() { super.onDestroy(); finished = true; } public void startActivity(View view) { startActivity(new Intent(this, MainActivity.class)); } public void startThread(View view) { thread.start(); } } 

Добавьте одну кнопку для запуска новой активности и одну для запуска потока. Начать новую деятельность. После возврата память будет очищена только в том случае, если поток не запущен.

В чем причина такого поведения?

Solutions Collecting From Web of "Объекты темы, а не сбор мусора после завершения"

Я только что решил эту проблему.

Томаш, ты на правильном пути. В DDMS нет ошибки, и в вашей программе нет утечки памяти.

На самом деле проблема заключается в том, что вы запускаете свою программу в режиме DEBUG (под Eclipse). Как-то, когда Android работает в режиме DEBUG, потоки не собираются с мусором даже после выхода метода run (). Я думаю, что, вероятно, Android должен поддерживать связь с Thread для некоторых функций отладки.

Но если вы запустили приложение в режиме RUN (все еще под Eclipse), происходит сборка мусора Thread. Тема будет полностью освобождена, и ваша активность будет полностью освобождена.

Я продолжал расследование, и то, что я нашел, действительно удивляет. Кажется, нет реальной утечки памяти. Это происходит только тогда, когда приложение находится в режиме отладки в DDMS.

Кажется, что DDMS каким-то образом ссылается на те готовые ступени, не позволяя им быть GC-ed. Когда я отсоединяю телефон и подключаюсь снова, я вижу, что все «утеченные» ресурсы были выпущены.

Это похоже на ошибку в DDMS.

Анонимный класс runnable, используемый потоком, будет ссылаться на активность («это»). Поскольку поток ссылается на активность, а runnable в потоке ссылается на активность, GC никогда не будет собирать ни один из них.

Попробуйте сделать что-то более похожее на это:

 private static RunnableClass implements Runnable { @Override public void run() { while (!finished) { try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } Log.d(getClass().getName(), "Thread finished"); } }); Thread thread = new Thread(new RunnableClass()); 

Действия не уничтожаются при нажатии «назад» или каких-либо других намерений, чтобы удалить его из верхней части стека. Я не думаю, что ваш метод overdend onDestroy () когда-либо называется, пока ваша ОС Android не исчерпается. Из документации можно извлечь:

Как обсуждается в следующем разделе о жизненном цикле активности, система Android управляет жизнью для вас, поэтому вам не нужно заканчивать свою деятельность. Вызов этих методов может неблагоприятно повлиять на ожидаемый пользовательский опыт и должен использоваться только тогда, когда вы абсолютно не хотите, чтобы пользователь возвращался к этому экземпляру активности.

Обычно каждый экземпляр Activity onStart()...onStop() в памяти после первоначального создания и проходит onStart()...onStop() без разрушения. onStop() и finish() вызов finish() в нем для MainActivity с MainActivity который будет выпущен, и, следовательно, собранный мусор.

UPDATE : Вышеприведенное утверждение неверно. Основываясь на кодексе, содержащемся в вопросе, нет причин, по которым деятельность не должна быть GC-ed.