Область действия участника и Asynctask

Я инициализирую переменную-член в классе Activity

private String test = new String("A"); 

То я использую его для записи в журнал долгое время цикла в doInBackground() метода анонимной AsyncTask, запущенной из Activity

 new AsyncTask<Void, Void, Void>() { @Override protected void onPreExecute() { } @Override protected void onPostExecute(Void result) { } @Override protected Void doInBackground(Void... params) { for (int j = 10; j >= 0; j--) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Log.i("DOINBACKGROUND ", test); } }.execute(); 

ВОПРОС : Когда я покидаю Activity, пока Asynctask все еще выполняется, и после выполнения onDestroy() Activity , я вижу в onDestroy() что переменная-член все еще жива и не уничтожена. Может кто-нибудь объяснить мне, как это возможно?

BOUNTY QUESTION : переменная-член все еще жива, потому что даже после onDestroy() она еще не сбрасывается из-за критериев gc и gc priority. Хорошо.

Но я сомневаюсь, что если

  • Переменная-член «test» (и контекст активности) не будет сбрасываться до тех пор, пока ссылочная асинтеза не закончит свою работу, поэтому asynctask может завершить ее doInBackground() всегда и без ошибок (хотя и с временным потреблением памяти)

Или вместо этого

  • Переменная-член «test» будет изнашиваться рано или поздно, независимо от того, выполняется ли асинтеза, возможно, в результате сбоя asysnctask

Solutions Collecting From Web of "Область действия участника и Asynctask"

Не путайте сбор мусора и жизненный цикл деятельности.

Объект может быть собран в мусор, как только все ссылки, отсылаемые к нему из объектов GC root, исчезнут.

onDestroy() является частью жизненного цикла деятельности. По сути, структура выполняется с помощью этой деятельности и отказывается от каких-либо ссылок, которые она могла бы удержать в отношении деятельности и связанных с ней ресурсов.

Когда вы создаете анонимный внутренний класс, он получает неявную ссылку на родительский объект. Другими словами, внутренний класс anon всегда является нестационарным внутренним классом. Эта родительская ссылка является ссылкой на вашу Activity . Затем вы передаете объект задачи async исполнителю с вызовом execute() и исполнитель сохраняет ссылку на асинхронную задачу до тех пор, пока это необходимо, а также предотвращает сбор данных, на которые ссылается активность.


Таким образом, asynctask в моем примере фрагмента завершает doInBackground () всегда и, конечно, без сбоев из-за NPE?

Да. Но учтите следующее:

  • Сделайте свои внутренние классы static если они специально не нуждаются в доступе к родительскому объекту. Поскольку внутренние классы anon всегда не static , сделайте их не анонимными.

  • Смешивание асинхронных операций с объектами с отдельным жизненным циклом (например, действия или фрагменты) является хрупким, и его лучше избегать. К таким проблемам относятся, например, аннулирование, доставка результатов на ушедший объект и поддержание ссылок на дорогостоящие объекты, такие как действия.

Прежде всего, onDestroy () происходит непосредственно перед уничтожением активности и просит диспетчера активности освободить все ресурсы, привязанные к этой активности. Это означает, что все ресурсы активности будут кандидатами на удаление gc. Однако он не заставляет gc удалять ресурсы из памяти, они просто кандидаты. Этот кандидат будет оцениваться gc на основе их размера, возраста, продолжительности, типа и т. Д., И всякий раз, когда системе требуется больше места, она просит gc удалить кандидатов, и это делается на основе их оценок. Кандидат с более высоким счетом, скорее всего, будет удален первым.

Это заметно, когда вы видите крушение из ниоткуда, даже после выхода из приложения.

Вы можете увидеть этот сбой, если вы создадите другое действие и вызовите System.gc () на нем.

Приветствия А.

Тест переменной-члена не будет возвращен сборщиком мусора до тех пор, пока экземпляр Activity не будет собран.

Экземпляр Activity не будет возвращен сборщиком мусора до тех пор, пока AsyncTask не будет завершен, потому что AsyncTask содержит ссылку на экземпляр Activity.

Экземпляр AsyncTask не будет собираться мусором, пока он не завершит свою работу.

AsyncTask завершит метод doInBackground() без сбоев. Наверняка.

AsyncTask не привязан к жизненному циклу Activity, который содержит его. Например, если вы запускаете AsyncTask внутри Activity и пользователь поворачивает устройство, действие будет уничтожено (и будет создан новый экземпляр Activity), но AsyncTask не умрет, а продолжит жизнь до его завершения.

Затем, когда AsyncTask завершает работу, а не обновляет интерфейс нового действия, он обновляет прежний экземпляр Activity (т. Е. Тот, в котором он был создан, но который больше не отображается!). Это может привести к исключению (типа java.lang.IllegalArgumentException: View не подключен к оконному менеджеру, если вы используете, например, findViewById, чтобы получить представление внутри Activity).

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

По этим причинам использование AsyncTasks для длительных фоновых задач, как правило, является плохой идеей. Скорее, для длительных фоновых задач должен использоваться другой механизм (например, служба).

Я предполагаю, что задача async не является статичной, и в ней содержится ссылка на включение активности, что предотвращает сбор мусора.

Если вы хотите знать, как анонимный класс может вызвать утечку активности, обратитесь сюда – ссылка

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

Adb shell dumpsys meminfo your.app.packagename

 Applications Memory Usage (kB): Uptime: 40343748 Realtime: 164852669 ** MEMINFO in pid 16561 [samsung.svl.com.graph] ** Pss Private Private Swapped Heap Heap Heap Total Dirty Clean Dirty Size Alloc Free ------ ------ ------ ------ ------ ------ ------ Native Heap 5708 5664 16 2380 20480 8849 11630 Dalvik Heap 1163 972 136 27080 37459 29598 7861 Dalvik Other 604 604 0 4 Stack 288 288 0 0 Other dev 4 0 4 0 .so mmap 3569 992 72 2120 .apk mmap 39 0 0 0 .ttf mmap 0 0 0 0 .oat mmap 539 0 4 0 .art mmap 747 524 4 704 Other mmap 5 4 0 0 GL mtrack 10951 10951 0 0 Unknown 2260 2260 0 92 TOTAL 25877 22259 236 32380 57939 38447 19491 Objects Views: 17 ViewRootImpl: 1 AppContexts: 3 **Activities: 1** Assets: 3 AssetManagers: 3 Local Binders: 8 Proxy Binders: 23 Parcel memory: 3 Parcel count: 12 Death Recipients: 0 OpenSSL Sockets: 0 SQL MEMORY_USED: 0 PAGECACHE_OVERFLOW: 0 MALLOC_SIZE: 0