Как / когда собирается мусор Handler?

Внутри моего класса у меня есть следующий код:

mHandler = createHandler(); private Handler createHandler() { return new Handler() { public void handleMessage (Message msg) { update(); if (!paused) { sendEmptyMessageDelayed(0, 300); } } }; } 

В документации говорится:

http://developer.android.com/reference/android/os/Handler.html

Каждый экземпляр Handler связан с одним потоком и очереди сообщений потока

Поэтому, если я правильно понял, обработчик не собирает мусор, пока работает поток приложений, это правильно?

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

Кстати, я могу заставить обработчика прекратить отправлять сообщения (вот почему у меня есть if (!paused) ), но это не сделает его GCed, так?

Так есть способ удалить обработчик из очереди сообщений и заставить его быть GCed?

Solutions Collecting From Web of "Как / когда собирается мусор Handler?"

В моем конкретном примере, поскольку обработчик является анонимным внутренним классом, он имеет неявную ссылку на охватывающий объект и всю иерархию объектов, на которые он указывает.

Вы могли бы уменьшить влияние потенциальной утечки почти на ничего, используя static вложенный класс вместо анонимного внутреннего класса.

Изучение источника обработчика показывает более подробную информацию.

Вот какой код отладки от конструктора Handler (), который был добавлен Роменом Гаем:

 if (FIND_POTENTIAL_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } 

Предупреждение ясно: не объявляйте подкласс Handler как внутренний класс.

Петлером обработчика получается из статического экземпляра ThreadLocal:

 mLooper = Looper.myLooper(); /** * Return the Looper object associated with the current thread. Returns * null if the calling thread is not associated with a Looper. */ public static final Looper myLooper() { return (Looper)sThreadLocal.get(); } 

Анатомия утечки:

В основном потоке приложения сохраняется Looper и MessageQueue, сообщения в очереди сохраняют ссылку на их целевого обработчика, а обработчик – если это не статический вложенный класс с WeakReference для вашей активности – сохранит вашу активность и ее Просмотры.

Вместо этого вы можете попытаться подключить эту утечку, очистив сообщения:

 handler.removeMessages(what); 

Но это легче сказать, чем сделать.

Также см. « Утечки памяти на Java» и на Android

Нет, прекратить отправку сообщения не делает работу GC. Как указывает док, он ограничивается ниткой, которая ее создает. Если поток запущен, обработчик не будет возвращен GC.

Почему вы думаете, что это может вызвать утечку памяти? Что вы подразумеваете под «неявной ссылкой на прилагаемый объект»?