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

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

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

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

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

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

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

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

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

Ответы [ 12 ]

7 голосов
/ 04 октября 2010

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

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

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

4 голосов
/ 29 января 2010

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

3 голосов
/ 29 января 2010

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

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

2 голосов
/ 29 января 2010

Я считаю, что MapMaker будет единственным разумным способом получить то, что вы просите. Если «ГХ начинает работать, а производительность всего приложения резко ухудшается», вам следует потратить некоторое время на правильную настройку различных параметров настройки. Поначалу этот документ может показаться немного пугающим, но на самом деле он написан очень четко и является золотой жилой полезной информации о GC: * ​​1002 *

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

1 голос
/ 29 января 2010

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

0 голосов
/ 23 марта 2012

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

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

0 голосов
/ 29 января 2010

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

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

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

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

0 голосов
/ 29 января 2010

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

0 голосов
/ 29 января 2010

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

0 голосов
/ 29 января 2010

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

...