Подтвердить что ты не робот

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

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

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

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

Вы просмотрели коллективные коллекции LRUMap?

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

Ответ 7

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

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

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

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

Ответ 11

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

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

Ответ 12

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