Как избежать утечек памяти при обратном вызове? - PullRequest
19 голосов
/ 18 мая 2010

Эффективная Java говорит:

Третий распространенный источник утечек памяти это слушатели и другие обратные вызовы. Если вы реализуете API, где клиенты регистрировать обратные вызовы, но не отмените их регистрацию, они накапливать, если вы не берете немного действие. Лучший способ обеспечить обратные вызовы являются мусором своевременно хранить только слабые ссылки на них, например, хранить их только как ключи в WeakHashMap.

Я новичок в Java. Может ли кто-нибудь научить меня создавать слабые ссылки в обратных вызовах и рассказать, как они решают проблемы утечки памяти? Спасибо.

Ответы [ 3 ]

13 голосов
/ 18 мая 2010

Читать это статья

Ключевые ключи:

Вы можете думать о прямых ссылках как сильные ссылки, которые не требуют дополнительное кодирование для создания или доступа к объект. Остальные три типа ссылки являются подклассами Ссылочный класс найден в пакет java.lang.ref. Мягкие ссылки предоставляются SoftReference класс, слабые ссылки со стороны WeakReference класс и фантом ссылки по PhantomReference.

Мягкие ссылки действуют как кеш данных. Когда системной памяти мало, мусор Коллектор может произвольно освободить объект, чья единственная ссылка является мягкой ссылка. Другими словами, если есть нет сильных ссылок на объект, этот объект является кандидатом на релиз. Сборщик мусора есть требуется выпустить любой софт ссылки, прежде чем бросать OutOfMemoryException.

Слабые ссылки слабее мягких Рекомендации. Если только ссылки на объект слабые ссылки, сборщик мусора может вернуть память, используемая объектом в любое время. Там нет требования для низкого ситуация с памятью. Как правило, память используемый объектом восстанавливается в очередной проход сборщика мусора.

Фантомные ссылки относятся к очистке задачи. Они предлагают уведомление непосредственно перед мусором коллектор выполняет доработку обрабатывает и освобождает объект. Рассматривать это способ сделать задачи по очистке в пределах объект.

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

8 голосов
/ 12 декабря 2011

Чтобы проиллюстрировать концепцию на быстром (сыром) примере, рассмотрим следующее:

public interface ChangeHandler {
    public void handleChange();
}

public class FileMonitor {

    private File file;
    private Set<ChangeHandler> handlers = new HashSet<ChangeHandler>();

    public FileMonitor(File file) { 
        this.file = file;
    }

    public void registerChangeHandler(ChangeHandler handler) {
        this.handlers.add(handler);
    } 

    public void unregisterChangeHandler(ChangeHandler handler) {
        this.handlers.remove(handler);
    }

    ...
}

Если клиентский класс затем использует этот FileMonitor API, они могут сделать это:

public class MyClass {

    File myFile = new File(...);
    FileMonitor monitor = new FileMonitor(myFile);

    public void something() {
        ...
        ChangeHandler myHandler = getChangeHandler();
        monitor.registerChangeHandler(myHandler);
        ...
    }
}

Если автор MyClass затем забудет вызвать unregisterChangeHandler(), когда это будет сделано с обработчиком, FileMonitor HashSet всегда будет ссылаться на зарегистрированный экземпляр, заставляя его оставаться в памятидо тех пор, пока FileMonitor не будет уничтожен или приложение не закроется.

Чтобы предотвратить это, Блох предлагает использовать коллекцию со слабыми ссылками вместо HashSet, так что если ваш экземпляр MyClass будет уничтожен,ссылка будет удалена из коллекции монитора.

Вы можете заменить HashSet in FileMonitor на WeakHashMap и использовать обработчики в качестве ключей, так как последний будетавтоматически удаляет обработчик из коллекции, когда все другие ссылки на объект исчезают.

1 голос
/ 22 июля 2016

Здесь вы можете найти ясное и практическое объяснение : Утечки памяти в Android - выявляйте, лечите и избегайте

...