Подтвердить что ты не робот

Область действия участника и 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() выполняется, я вижу в журнале, что переменная-член все еще жива и не уничтожена. Может кто-нибудь объяснить мне, как это возможно?

ВОСЬМОЙ ВОПРОС: переменная-член все еще жива, потому что даже после onDestroy() она еще не сбрасывается из-за критериев gc и приоритета gc. Это нормально.

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

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

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

  • переменная-член "test" будет изнашиваться рано или поздно, независимо от того, запущена ли асинтеза, возможно, приведет к сбою asysnctask
4b9b3361

Ответ 1

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

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

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

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


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

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

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

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

Ответ 2

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

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

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

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

Ответ 3

Членная переменная test не будет возвращена сборщиком мусора, пока экземпляр Activity не будет собран.

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

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

AsyncTask завершит метод doInBackground() без сбоев. Конечно.

Ответ 4

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

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

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

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

Ответ 5

Я предполагаю, что задача 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