У меня есть некоторые утечки памяти в моем приложении. Все они происходят вокруг определенного кластера представлений, в котором я потратил время на настройку времени и попытался максимально сократить контекстуальную передачу. Это заставляет меня думать, что растровые изображения, используемые в кластере, являются проблемой. Поэтому я думал использовать WeakReferences для всех ссылок на растровые изображения, используемые представлениями. Я никогда не использовал WeakReference и не уверен, что это хорошее приложение. Может ли любой орган предоставить полезные указатели или подсказки?
Каковы преимущества использования WeakReferences?
Ответ 1
Итак, я думал использовать WeakReferences для всех ссылок на растровые изображения, используемые представлениями. у меня есть никогда не использовал WeakReference, и я не если это хорошее приложение. Может ли любой орган обеспечить полезную указатели или подсказки?
Будьте осторожны, это опасно в вашем случае. GC может избавиться от всех ваших растровых изображений, в то время как ваше приложение может все еще нуждаться в них.
Ключевой проблемой WeakReference является понимание разницы с жесткими ссылками. Если в приложении нет более жесткой ссылки на растровое изображение, GC может автоматически удалять объект из памяти, и вся существующая слабая ссылка мгновенно указывает на нуль. В вашем случае вы НЕ МОЖЕТЕ использовать слабые ссылки по всему вашему коду.
Вот идея решения. Создайте объект-контейнер, который будет поддерживать слабые ссылки (только) на все ваши растровые изображения. Ваши взгляды всегда должны ссылаться на растровые изображения только с жесткими ссылками. Когда представление создает растровое изображение, оно должно зарегистрировать его в объекте-контейнере. Когда он хочет использовать представление, он должен получить жесткую ссылку из контейнера.
Таким образом, если никакие представления не относятся к растровому изображению, GC собирает объект без побочных эффектов для представлений, так как ни один из них не имеет жесткой ссылки на него. При использовании объектов с низкой ссылочной позицией, хорошая практика явно устанавливать жесткие ссылки на нуль, когда вам больше не нужен объект.
Добавление
Вот краткая реализация решения (просто для того, чтобы дать представление):
public class BitmapContainer {
public static class Bitmap {
private final long id;
public Bitmap(long id) { this.id = id; }
public long getId() { return id; }
public void draw() { };
}
WeakHashMap<Bitmap, WeakReference<Bitmap>> myBitmaps
= new WeakHashMap<Bitmap, WeakReference<Bitmap>>();
public void registerBitMap(Bitmap bm) {
if ( bm == null ) throw new NullPointerException();
WeakReference<Bitmap> wr = new WeakReference<Bitmap>(bm);
myBitmaps.put(bm, wr);
}
/** Method returns null if bitmap not available */
public Bitmap getBitMap(long id) {
for ( Bitmap item : myBitmaps.keySet() ) {
if ( item != null) {
if ( item.getId() == id ) {
return item;
}
}
}
return null;
}
}
Ответ 2
Наиболее прямолинейное использование слабых ссылок, о которых я могу думать, - это кеш. Вы хотите добавить объекты в кэш, но если в остальной части виртуальной машины нет ссылок на объект, вы хотите, чтобы объект получил GC'ed без необходимости возвращаться и самостоятельно удалять его из кэша. Слабые ссылки достигают этого. Вы добавляете слабую ссылку на объект в вашем кеше. Когда кеш - это единственное, что относится к вашему объекту, он имеет право на GC. Попытки использовать слабую ссылку после объекта GC'ed приводят к исключению.
Строго говоря, объект имеет право на GC, если нет сильных ссылок на него (т.е. существуют ли какие-либо слабые ссылки на него).
Основываясь на вашем описании вашей ситуации, неясно, что вам помогут слабые ссылки. Но если вы столкнулись с ситуацией, когда вам нужно преднамеренно очистить ссылки на объекты, которые больше не нужны, то слабыми ссылками может быть решение. Вы просто должны быть уверены, что, когда остаются только слабые ссылки, на самом деле все в порядке, чтобы избавиться от объекта.
Ответ 3
Необходимость для WeakReferences происходит из сценария, в котором вам нужно поддерживать метаданные об объекте, для которого вы не контролируете.
Настроенный пример будет String
, он окончательный, и мы не можем его расширять, но если мы хотим сохранить некоторые дополнительные данные об определенном экземпляре String
, мы, скорее всего, будем использовать реализацию Map
, которая будет содержать эти метаданные. В этом примере я предлагаю, чтобы мы сохранили длину строки в качестве наших метаданных (да, я знаю, что объект String
уже имеет свойство общей длины). Поэтому мы создали бы Map
следующим образом:
Map<String, Integer> stringLengths = new HashMap<String, Integer>();
Предположим, что мы можем заполнить эту карту в некотором методе и не знать, когда мы закончили с данными, поэтому мы не можем явно удалить записи. Когда мы заполняем эту карту, которая никогда не будет незаселенна, наши ссылки будут храниться навсегда. Если приложение работает в течение длительного времени, есть хороший шанс, что мы столкнемся с OutOfMemoryError.
Решением этого будет использование реализации WeakHashMap
.
Map<String, Integer> stringLengths = new WeakHashMap<String, Integer>();
Таким образом, когда все (сильные) ссылки на ключ исчезнут, следующий GC вызовет удаление элемента WeakHashMap
. (Да, я понимаю, что String
имеет особое место в основе JVM, но я предполагаю, что String GC'd так же, как обычный Object будет в этом надуманном примере)
Если это подход, который вы используете в своем приложении (сохраняете свои растровые изображения на глобальной карте), я думаю, что это определенно нужно изучить.
Ответ 4
Я не думаю, что это правильное решение вашей проблемы. Как говорили другие, если вы используете WeakReferences, вы делаете свой код более дорогим и более хрупким. Хрупкость возникает, потому что каждый раз, когда вы используете слабую ссылку, вы можете получить исключение.
(Еще одна проблема заключается в том, что WeakReferences дороже, чем обычные ссылки для GC, с которыми приходится иметь дело. У меня нет фактических номеров производительности, и это, скорее всего, не имеет отношения к вашему делу, но это по крайней мере теоретическая проблема.)
IMO, лучший подход к вашей проблеме - использовать хороший профилировщик памяти, чтобы отслеживать, где происходит утечка памяти, и исправить ее. Запустите приложение на бит, используя профилировщик памяти, определите некоторый объект, который просочился, и используйте профилировщик для отслеживания пути или путей, по которым объект по-прежнему доступен. Вероятно, вы обнаружите, что это можно проследить до одной или двух ошибок или повторить один и тот же шаблон ошибки в нескольких местах. (Мое предположение - это прослушиватели событий, которые не удаляются в нужное время.)