Как мне эффективно кэшировать объекты в Java, используя доступную оперативную память?

StackOverflow https://stackoverflow.com/questions/2158868

Вопрос

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

Мои требования таковы:

  • Простой и легкий
  • Не намного медленнее, чем обычная хэш-карта
  • Используйте LRU или какую-либо политику удаления, которая приближена к LRU

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

Мой текущий подход заключается в использовании картографа Google Collection следующим образом:

Map<String, Object> cache = new MapMaker().softKeys().makeMap();

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

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

Это было полезно?

Решение

У меня похожие требования к вам - параллелизм (на 2 процессорах hexacore) и LRU или что-то подобное - и я также попробовал Guava MapMaker.Я обнаружил, что softValues() намного медленнее, чем weakValues(), но оба они делали мое приложение мучительно медленным при заполнении памяти.

Я попробовал WeakHashMap, и это было менее проблематично, как ни странно, даже быстрее, чем использовать LinkedHashMap в качестве кэша LRU через его метод removeEldestEntry().

Но самым быстрым для меня является Concurrentlink - хэш - карта что сделало мое приложение в 3-4 (!!) раза быстрее, чем любой другой кэш, который я пробовал.Радость после дней разочарований!По-видимому, это было включено в картограф Guava, но функции LRU в любом случае нет в Guava r07.Надеюсь, у вас это сработает.

Другие советы

Я внедрил serval-кэши, и это, вероятно, так же сложно, как реализовать новый источник данных или threadpool, моя рекомендация - использовать jboss-cache или другую хорошо известную кэширующую библиотеку.Так что вы будете хорошо спать без проблем

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

Я действительно не знаю, можно ли так сказать Тайник является тяжеловесным.По крайней мере, я не рассматриваю EHCache как таковой, особенно при использовании Хранилище памяти (который подкреплен расширенным LinkedHashMap и, конечно же, это самый быстрый вариант кэширования).Вы должны дать ему попробовать.

Я верю MapMaker это будет единственный разумный способ получить то, о чем вы просите.Если "GC начинает барахлить и производительность всего приложения резко ухудшается", вам следует потратить некоторое время на правильную настройку различных параметров настройки.На первый взгляд этот документ может показаться немного пугающим, но на самом деле он написан очень четко и является кладезем полезной информации о GC:

http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf

Я не знаю, было бы ли это простым решением, особенно по сравнению с EHCache или подобным, но смотрели ли вы на Библиотека Javolution ( Javolution library )?Он не предназначен как таковой, но в javolution.context package у них есть шаблон распределителя, который может повторно использовать объекты без необходимости сборки мусора.Таким образом, они сводят к минимуму создание объектов и сборку мусора, что является важной функцией для программирования в реальном времени.Возможно, вам следует взглянуть и попытаться адаптировать его к вашей проблеме.

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

Использование программных клавиш просто позволяет сборщику мусора удалять объекты из кэша, когда никакие другие объекты не ссылаются на них (т. е. когда единственное, что ссылается на ключ кэша, - это сам кэш).Это не гарантирует никакого другого вида высылки.

Большинство решений, которые вы найдете, будут функциями, добавленными поверх классов java Map, включая EhCache.

Вы смотрели на commons-коллекции ЛРУМап?

Обратите внимание, что существует открытый вопрос против MapMaker для обеспечения функциональности LRU / MRU.Возможно, вы сможете высказать свое мнение и там

Используя существующий кеш, храните WeakReference вместо обычных ссылок на объекты.

Если в GC начнет заканчиваться свободное место, значения, хранящиеся в WeakReferences, будут освобождены.

В прошлом я использовал JCS.Вы можете настроить конфигурация чтобы попытаться удовлетворить ваши потребности.Я не уверен, что это будет соответствовать всем вашим требованиям, но я обнаружил, что это довольно мощно, когда я его использовал.

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

Я не знаю простого способа узнать размер объекта в Java.Поэтому я не думаю, что вы найдете способ ограничить структуру данных объемом оперативной памяти, который она занимает.

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

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

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

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

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

Предполагая, что вы хотите, чтобы кэш был потокобезопасным, тогда вам следует изучить пример кэша в книге Брайана Гетца "Параллелизм Java на практике".Я не могу рекомендовать это достаточно высоко.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top