Как эффективно кэшировать объекты в Java, используя доступную ОЗУ?
Мне нужно кэшировать объекты на Java, используя долю любой доступной ОЗУ. Я знаю, что другие задавали этот вопрос, но ни один из ответов не отвечает моим требованиям.
мои требования:
- простой и легкий
- не значительно медленнее, чем простой HashMap
- используйте LRU или некоторую политику удаления, которая приближается к LRU
я попробовал LinkedHashMap, однако для этого требуется указать максимальное количество элементов, и я не знаю, сколько элементов потребуется для заполнения доступной оперативной памяти (их размеры будут значительно отличаться).
мой текущий подход заключается в использовании картографа Google Collection следующим образом:
Map<String, Object> cache = new MapMaker().softKeys().makeMap();
Это казалось привлекательным, поскольку он должен автоматически удалять элементы, когда ему нужно больше ОЗУ, однако есть серьезная проблема: его поведение состоит в том, чтобы заполнить всю доступную ОЗУ, в этот момент GC начинает бить и производительность всего приложения резко ухудшиться.
Я слышал о таких вещах, как EHCache, но он кажется довольно тяжелым для того, что мне нужно, и я не уверен, достаточно ли он быстр для моего приложения (помня, что решение не может быть значительно медленнее, чем HashMap).
12 ответов
У меня есть аналогичные требования к вам-параллелизм (на 2 процессорах hexacore) и LRU или аналогичный - а также попробовал Guava MapMaker. Я нашел softValues () намного медленнее, чем weakValues (), но оба сделали мое приложение мучительно медленным, когда память заполнилась.
Я попробовал WeakHashMap, и это было менее проблематично, странно даже быстрее, чем использование LinkedHashMap в качестве кэша LRU с помощью метода removeEldestEntry ().
но самым быстрым для меня является ConcurrentLinkedHashMap что сделало мое приложение 3-4 (!!) раз быстрее, чем любой другой кэш, который я пробовал. Радость, после нескольких дней разочарования! По-видимому, он был включен в составитель карт гуавы, но функция LRU в любом случае не находится в Guava r07. Надеюсь, это сработает.
я реализовал кэши serval, и это, вероятно, так же сложно, как реализовать новый источник данных или threadpool, моя рекомендация-использовать JBoss-cache или другой известный кэширующий lib. Так что вы будете спать хорошо без проблем
Я слышал о таких вещах, как EHCache, но он кажется довольно тяжелым для того, что мне нужно, и я не уверен, достаточно ли он быстр для моего приложения (помня, что решение не может быть значительно медленнее, чем HashMap).
Я действительно не знаю, можно ли это сказать EHCache тяжелая-вес. По крайней мере, я не рассматриваю EHCache как таковой, особенно при использовании Память (который поддерживается расширенным LinkedHashMap
и, конечно же, самый быстрый вариант кэширования). Тебе стоит попробовать.
Я считаю MapMaker
будет единственным разумным способом получить то, что вы просите. Если "GC начинает трястись, и производительность всего приложения резко ухудшается", вы должны потратить некоторое время на правильную настройку различных параметров настройки. Этот документ может показаться немного пугающим на первый взгляд, но на самом деле он написан очень четко и является золотой жилой полезной информации о GC:
http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf
Я не знаю, будет ли это простое решение, особенно по сравнению с EHCache или подобным, но вы посмотрели на библиотека Javolution? Он не предназначен для как таковой, а в javolution.context
пакет они имеют шаблон распределителя, который может повторно использовать объекты без необходимости сбора мусора. Таким образом, они сводят к минимуму создание объектов и сборку мусора, что является важной особенностью программирования в реальном времени. Возможно, вам стоит взглянуть и попытаться адаптировать его к твоя проблема.
Это казалось привлекательным, как и должно быть автоматически удалять элементы, когда это требуется больше ОЗУ, однако есть серьезная проблема: свое поведение к заполните все доступные ОЗУ
использование программных ключей позволяет сборщику мусора удалять объекты из кэша, когда никакие другие объекты не ссылаются на них (т. е. когда единственное, что ссылается на ключ кэша, - это сам кэш). Он не гарантирует никаких других видов высылки.
большинство решения, которые вы найдете, будут добавлены поверх классов карт java, включая EhCache.
вы смотрели достояния-коллекции LRUMap?
обратите внимание, что есть открыть вопрос против MapMaker для обеспечения функциональности LRU / MRU. Возможно, вы можете высказать свое мнение и там
используя ваш существующий кэш, каждого магазина, а не нормальный refererences объекта.
Если GC запускается из свободного пространства, значения WeakReferences выйдет.
в прошлом я использовал JCS. Вы можете настроить конфигурация попытаться удовлетворить ваши потребности. Я не уверен, что это будет соответствовать всем вашим требованиям / потребностям, но я нашел его довольно мощным, когда использовал его.
вы не можете "удалить элементы", вы можете только остановиться, чтобы жестко ссылаться на них и ждать, пока GC очистит их, поэтому продолжайте с коллекциями Google...
Я не знаю простого способа узнать размер объекта в Java. Поэтому я не думаю, что вы найдете способ ограничить структуру данных количеством ОЗУ, которое она принимает.
основываясь на этом предположении, вы застряли с ограничением его количеством кэшированных объектов. Я бы предложил запустить моделирование нескольких реальных сценариев использования и собрать статистику по типам объектов, которые входят в кэш. Затем вы можете вычислить статистически средний размер и количество объекты, которые можно кэшировать. Хотя это всего лишь приблизительное количество ОЗУ, которое вы хотите посвятить Кешу, это может быть достаточно хорошо.
Что касается реализации кэша, в моем проекте (критически важном для производительности приложении) мы используем EhCache, и лично я не считаю его тяжеловесом вообще.
в любом случае, выполните несколько тестов с несколькими различными конфигурациями (относительно размера, политики выселения и т. д.) и выяснить, что лучше всего подходит для вы.
кэширование чего-то, SoftReference
может, лучший способ до сих пор я могу себе представить.
или вы можете изобрести пул объектов. Что каждый объект, который вы не используете, вам не нужно уничтожать. Но это, чтобы сохранить CPU, а не сохранить память
предполагая, что вы хотите, чтобы Кэш был потокобезопасным, тогда вы должны изучить пример кэша в книге Брайана Гетца "параллелизм Java на практике". Я не могу рекомендовать это достаточно высоко.