Каковы преимущества использования WeakReferences? - PullRequest
11 голосов
/ 25 мая 2011

У меня есть некоторые утечки памяти в моем приложении.Все они происходят вокруг определенного кластера представлений, который я потратил много времени, настраивая и пытаясь максимально сократить контекстную передачу.Это приводит меня к мысли, что проблема заключается в использовании растровых изображений в кластере.Поэтому я думал использовать WeakReferences для всех ссылок на растровые изображения, используемые представлениями.Я никогда не использовал WeakReference и не уверен, что это хорошее приложение.Может ли какой-либо орган предоставить полезные указатели или советы?

Ответы [ 4 ]

15 голосов
/ 25 мая 2011

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

Будьте осторожны, это опасно в вашем случае. GC может избавиться от всех ваших растровых изображений, в то время как ваше приложение может по-прежнему нуждаться в них.

Ключевая проблема WeakReference - понять разницу с жесткими ссылками. Если в вашем приложении нет более жесткой ссылки на растровое изображение, тогда GC разрешается атомарно удалять объект из памяти, и все существующие слабые ссылки мгновенно указывают на ноль. В вашем случае вы НЕ МОЖЕТЕ использовать слабые ссылки по всему коду.

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

Таким образом, если ни одно из представлений не ссылается на растровое изображение, то ГХ будет собирать объект без побочных эффектов для представлений, поскольку ни одно из них не имеет жесткой ссылки на него. При использовании объектов со слабыми ссылками рекомендуется устанавливать жесткие ссылки на null, если объект больше не нужен.

Сложение

Вот быстрая реализация решения (просто чтобы дать представление):

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;

    }

}
4 голосов
/ 25 мая 2011

Самое прямое использование слабых ссылок, о которых я могу подумать, - это кэш.Вы хотите добавить объекты в кеш, но если в остальной части виртуальной машины нет ссылок на объект, вы хотите, чтобы объект получил GC, без необходимости возвращаться и удалять его из кеша самостоятельно.Слабые ссылки достигают этого.Вы добавляете слабую ссылку на объект в свой кеш.Когда кеш является единственным, что относится к вашему объекту, он имеет право на сборщик мусора.Попытки использовать слабую ссылку после того, как объект является GC-результатом, приводят к исключению.

Строго говоря, объект имеет право на GC, когда не остается никаких strong ссылок на него (т.е.слабых ссылок на него не существует).

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

3 голосов
/ 25 мая 2011

Потребность в 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, но я предполагаю, что строки - это GC так же, как обычный объект в этом надуманном примере)

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

1 голос
/ 25 мая 2011

Я не думаю, что это правильное решение вашей проблемы.Как уже говорили другие, если вы используете WeakReferences, вы делаете свой код более дорогим и более хрупким.Хрупкость возникает потому, что каждый раз, когда вы используете слабую ссылку, вы потенциально можете получить исключение.

(Другая проблема заключается в том, что WeakReferences обходятся GC дороже, чем обычные ссылки. У меня нет реальных цифр производительности, и это, скорее всего, не имеет значения в вашем случае использования, ноэто, по крайней мере, теоретическая проблема.)

IMO, лучший подход к вашей проблеме - использовать хороший профилировщик памяти, чтобы отследить, где на самом деле происходят утечки памяти, и исправить это.Немного запустите приложение, используя профилировщик памяти, определите утекший объект и используйте профилировщик для отслеживания пути или путей, по которым объект все еще доступен.Вы, вероятно, обнаружите, что это может быть связано с одной или двумя ошибками или с тем же шаблоном ошибки, повторенным в нескольких местах.(Я предполагаю, что слушатели событий не будут удалены в нужное время.)

...