Почему мой механизм кэширования не работает должным образом? - PullRequest
3 голосов
/ 01 марта 2012

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

public class BitmapCache {
    private static final int MAX_NUMBER_BITMAPS_TO_CACHE = 30;
    private static Map<String, Bitmap> bitmapCache = new HashMap<String, Bitmap>();
    private static List<String> cachedBitmapUrlsOrder = new ArrayList<String>();

    private BitmapCache(){}

    public static synchronized void addBitmapToCache(String url, Bitmap bitmap) {
        if (bitmapCache.size() >= MAX_NUMBER_BITMAPS_TO_CACHE) {
            Log.i("MyApp", "Max cache size reached.  Removing oldest bitmap.  Size = " + bitmapCache.size());
            String oldestUrl = cachedBitmapUrlsOrder.remove(0);
            bitmapCache.remove(oldestUrl);
        }
        bitmapCache.put(url, bitmap);
        cachedBitmapUrlsOrder.add(url);
    }

    public static int size() {
        return bitmapCache.size();
    }

    public static Bitmap get(String url) {
        return bitmapCache.get(url);
    }

    public synchronized static void clearCache() {
        bitmapCache.clear();
    }
}

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

02-29 23:00:26.590: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.600: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.720: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.790: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 30
02-29 23:00:26.820: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 31
02-29 23:00:26.850: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 31
02-29 23:00:27.050: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 32
02-29 23:00:27.070: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 32
02-29 23:00:27.100: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 33
02-29 23:00:27.130: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 34
02-29 23:00:27.170: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.210: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.330: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35
02-29 23:00:27.360: I/MyApp(10789): Max cache size reached.  Removing oldest bitmap.  Size = 35

Код правильно начинает регистрировать «Максимальный размер кэша достигнут», когда размер кэша достигает 30, и остается там в течение нескольких выполнений. Но затем он странным образом начинает увеличиваться до 35. В этот момент он остается там для еще сотен результатов. Я не могу заставить его превысить 35.

Что не так с моей реализацией? Учитывая, что метод addBitmapToCache синхронизирован, я озадачен тем, как размер кэша может превысить установленный максимум.

Ответы [ 2 ]

2 голосов
/ 01 марта 2012

Кроме того, ответ Грэма, если вызов сделан на clearCache, cachedBitmapUrlsOrder не очищается. Поэтому, когда вы в следующий раз достигнете предела, вы не будете ничего удалять здесь:

String oldestUrl = cachedBitmapUrlsOrder.remove(0);
bitmapCache.remove(oldestUrl); // bitmapCache does not have such key
2 голосов
/ 01 марта 2012

Несколько проблем.

Во-первых, cachedBitmapUrlsOrder - это List. Что происходит с ним, если один и тот же битовый массив запрашивается более одного раза? Вы получаете целую кучу повторяющихся URL-адресов в списке. Поэтому, когда вы впервые достигнете предела, вы удаляете URL из списка и с карты. Но тот же URL все еще находится в списке, без соответствующей записи на карте . Поэтому последующие попытки удалить тот же URL из списка не удалят что-либо с карты, и карта будет расти.

Этого можно избежать, проверив в самом начале addBitmapToCache(), если URL-адрес уже кэширован, с помощью bitmapCache.containsKey(url). Если это так, вам не нужно изменять карту; просто убедитесь, что эта запись запомнена как самая последняя.

В качестве альтернативы, измените список на набор уникальных значений; вероятно, карта URL-адресов к временным меткам или набор. (Я позволю тебе решить.)

Кроме того, методы get() и size() также должны быть синхронизированы.

И get() должны обновить временную метку найденной записи, чтобы она стала самой последней.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...