2016-09-16 2 views
0

В моем приложении у меня есть другой вид списка, содержащий несколько эскизов. Сегодня я начинаю рефакторинг, и я хочу реализовать кэширование LRU. Я следую линиям Android, но мне интересно, стоит ли инициализировать только один LRU Cache для всего приложения или лучше инициализировать кеш LRU для каждого вида списка. Я боюсь outOfMemory. Таким образом, у меня есть следующие вопросы, на которые я не могу ответить сам: - один LRU-кеш, инициализированный одноэлементным рисунком, является хорошей идеей? - если память низкая, приводит ли ситуация outOfMemory к следующей инициализации LRU Cache?LRU Cache: инициализировать только один для всего приложения?

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    ... 
    // Get max available VM memory, exceeding this amount will throw an 
    // OutOfMemory exception. Stored in kilobytes as LruCache takes an 
    // int in its constructor. 
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024); 

    // Use 1/8th of the available memory for this memory cache. 
    final int cacheSize = maxMemory/8; 

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
     @Override 
     protected int sizeOf(String key, Bitmap bitmap) { 
      // The cache size will be measured in kilobytes rather than 
      // number of items. 
      return bitmap.getByteCount()/1024; 
     } 
    }; 
    ... 
} 
  • если память мала, кэш LRU автоматически освобождается? Мне интересно, будет ли у приложения проблемы с выпуском памяти, когда я использую LRU Cache (из-за сбоя приложения из-за нехватки памяти?)

  • Только один LRU-кеш для всего приложения, может быть проблемой?

  • Более одного кэша LRU для всего приложения, может быть, проблема?

ответ

1

У меня было много проблем с этим, поэтому я могу дать вам полезные ответы здесь.

Если память низкая, кэш LRU автоматически освобождается? Я интересно, если приложение будет иметь проблемы, чтобы освободить память, если я использую LRU кэша

LRU кэш будет не автоматически освободить память. Вам необходимо будет вытеснить записи программно.

Только один LRU-кеш для всего приложения, может быть, проблема?

Более одного кэша LRU для всего приложения, может ли это быть проблемой?

Класс LruCache - это общий класс с типом для ключа и типом для значения. Я бы сказал, что вы хотите иметь один LRU Cache для каждого типа объекта, который вы кешируете. Вы делаете то, что я сделал: кеширование Bitmap s и ввод с String s.

Только примечание стороны: Будьте осторожны с использованием bitmap.getByteCount(). JavaDocs говорят об этом:

Начиная с KITKAT, результат этого метода больше не может использоваться для определения использования памяти растрового изображения. См. getAllocationByteCount().

Я использовал LRU Cache для Bitmap s. Я думал, что достаточно переопределить Application.onTrimMemory() и очистить кеш всякий раз, когда вызывается этот метод.

Кроме того, я сделал то же самое, что и вы, и задал размер кеша на основе некоторого процента памяти кучи, доступного для приложения.

Но вот что произойдет: когда мое приложение было в состоянии низкой памяти, и мое приложение попытается загрузить изображение с недостаточной памятью, GC будет работать, но BitmapFactory все равно не сможет выделить память для Bitmap. Журналы показывали, что метод onTrimMemory() назывался асинхронно, иногда почти через секунду после того, как был выброшен OutOfMemoryError!

ЭЙ GOOGLE: ЕСЛИ СИСТЕМА НЕ МОЖЕТ СКАЗАТЬ МНЕ Я НИЗКИЙ НА ПАМЯТИ ДО ПОСЛЕOutOfMemoryError брошены, КАК В чёрте я должен администрировать мою память?

Безумие. Ясное, полное безумие.

Вот что я в конечном итоге делает: я бы поймать OutOfMemoryError в блоке Ьгу, очистить кэш там повторите запрос изображения на сервер. Точная вещь, которую они говорят вам не делать. Но это закончилось тем, что я исправил свою проблему. Теперь приложение намного стабильнее.

Итак, после того, как вы реализуете свой LRU-кеш, убедитесь, что вы стресс-тест вашего приложения; попробуйте перевести его в ситуацию с низкой памятью и посмотреть, как он себя ведет. Для меня это работало лучше всего при использовании эмулятора. Эмулятор имел бы небольшой предел в 96 Мб, но если бы он имел высокое разрешение экрана, ресурсы изображения масштабировались бы довольно большими, что делало бы то, что память максимально мала.

Если вы отображение эскизов, но вы получаете изображения с сервером, и они могут быть больше, чем ваш ImageView, убедитесь, что вы читаете эту статью: Loading Large Bitmaps Efficiently | Android Developers, чтобы узнать, как загрузить растровые изображения соответствующего размера без потери памяти.

Вы также можете поэкспериментировать с тем, чтобы система выполняла кэширование и настраивала HttpResponseCache.

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

И будьте готовы иметь дело с небольшим разочарованием.

+0

Привет! В это время я инициализирую weakHashMap в конструкторе listview, и я помещаю миниатюры на эту карту. Я думал, что лучше использовать LRU-кеш, но после прочтения вашего ответа я немного напуган. – aeroxr1

+1

Я просто посмотрел на «WeakHashMap». Я не понимал, что это * ключи *, которые имеют слабую ссылку в этом классе, а не значения. По этой причине, я думаю, вы можете сделать такую ​​карту как «Map >». Я сейчас желаю, чтобы я сделал это для начала. Поскольку класс 'LruCache' не имеет никаких скрытых связей с GC, он почти бесполезен. Таким образом, вы можете быть на правильном пути. Просто проверьте дерьмо из этого, и если он ведет себя приемлемо, объявите победу и назовите это днем. –

+0

В слабой хэш-карте это ключ, который имеет слабую ссылку ??? действительно ? Я этого не знал !!! – aeroxr1

Смежные вопросы