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

Как избежать утечек памяти при обратном вызове?

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

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

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

4b9b3361

Ответ 1

Прочитайте эту статью

Ключом выберем:

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

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

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

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

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

Ответ 2

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

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);
    }

    ...
}

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

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 на FileMonitor на WeakHashMap и использовать обработчики в качестве ключей, поскольку последний будет автоматически удалите обработчик из коллекции, когда все другие ссылки на объект исчезнут.