Любые кэши Java, которые могут ограничить использование памяти в кеше в памяти, а не только счет экземпляра?

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

Я понимаю, что трудно определить точное использование памяти для данного объекта без сериализации (чего я хочу избежать в общем случае из-за его медлительности, поражает цель моих применений), и я в порядке с предоставлением размера оцените себя.

Итак: существует ли простой кеш Java с открытым исходным кодом, который позволяет определять "вес" кешированных объектов, чтобы ограничить количество кешированных вещей?

EDIT (ноябрь 2010 г.): для чего стоит новый проект под названием Java CacheMate, который пытается решить эту проблему, с некоторыми другими идеями улучшения (многоуровневое кэширование в оперативной памяти)

Ответ 1

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

Размер памяти можно определить, включив Java-агент, и использование довольно просто при использовании утилиты SizeOf (http://sourceforge.net/projects/sizeof), Я использовал это только для целей отладки, и я бы рекомендовал провести сравнительный анализ накладных расходов, прежде чем принимать его для нормального использования.

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

Если вам это действительно нужно, и я бы посоветовал не делать этого, мы могли бы улучшить мою текущую реализацию, чтобы поддержать это. Вы можете написать мне по электронной почте ben.manes-at-gmail.com.

Ответ 2

Как насчет использования простой LinkedHashMap с включенным алгоритмом LRU и поместить в него все данные с помощью SoftReference... например cache.out(key, new SoftReference (значение))?

Это ограничило бы ваш кеш объемом доступной памяти, но не убил бы остальную часть вашей программы, потому что Java удаляет мягкие ссылки, когда есть потребность в памяти... не все.. самые старые сначала... обычно. Если вы добавите ссылочную очередь в свою реализацию, вы также можете удалить записи сваливания (только ключ, без значения) с карты.

Это освободит вас от вычисления размера записей и отслеживания суммы.

Ответ 3

В настоящее время EhCache V2.5 предлагает решение, которое может быть ограничено размером памяти в кеше. Для получения дополнительной информации проверьте Документация EhCache 2.5

Ответ 4

Не сложно измерить - трудно определить.

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

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

Ответ 5

Как и угадывание использования памяти для объекта, для разумного алгоритма вам также нужно угадать стоимость его воссоздания. Разумно предположить, что стоимость отдыха примерно пропорциональна размеру памяти. Таким образом, факторы отменяют друг друга, и вам тоже этого не нужно. Простой алгоритм, вероятно, будет лучше работать.

Ответ 6

Если вы не можете делать какие-либо оценки - напишите политику выключения кэша, которая сбрасывается на основе размера кучи JVM (опроса из системы) или инициируется завершением() - вызовом от осиротевшего объекта (на GC).

Ответ 7

Можно определить значимую меру для использования памяти в кеше. Вы можете вычислить: "сохраненный размер" . К сожалению, вычисление сохраненного размера примерно так же дорого, как и полный GC, и поэтому, вероятно, это не вариант. На определенных JVM-языках (clojure?) Вы могли бы теоретически убедиться, что ни один объект в кеше не будет ссылаться на внешние объекты, а затем вы могли бы контролировать реальный размер кеша.

Ответ 8

Вещью, выполняющей эту работу, является java.lang.ref.SoftReference. Как правило, вы расширяете класс SoftReference, чтобы подкласс содержал ключ.