EDIT: Я реорганизовал этот вопрос, чтобы отразить новую информацию, которая с тех пор стала доступной.
Этот вопрос основан на ответах на вопрос Viliam в отношении использования Guava Maps ленивого выселения: Лень выселения на картах Гуавы
Пожалуйста, сначала прочтите этот вопрос и его ответ, но по существу вывод состоит в том, что карты Гуавы не асинхронно вычисляют и не принуждают к выселению. Учитывая следующую карту:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.expireAfterAccess(10, TimeUnit.MINUTES)
.makeMap();
Как только десять минут пройдут после доступа к записи, оно все равно не будет выведено, пока карта не будет "тронута" снова. Известные способы сделать это включают обычные аксессоры - get()
и put()
и containsKey()
.
Первая часть моего вопроса [решена]: какие другие вызовы заставляют карту "трогать"? В частности, кто-нибудь знает, попадает ли size()
в эту категорию?
Поводом для этого является то, что я выполнил запланированную задачу, чтобы иногда подталкивать карту Guava, которую я использую для кэширования, используя этот простой метод:
public static void nudgeEviction() {
cache.containsKey("");
}
Однако я также использую cache.size()
, чтобы программно сообщать количество объектов, содержащихся на карте, так как способ подтверждения этой стратегии работает. Но я не мог видеть различия в этих отчетах, и теперь мне интересно, может ли size()
выселить.
Ответ: Итак, Марк указал, что в версии 9 выселение вызывается только методами get()
, put()
и replace()
, что объясняет, почему я не был видя эффект для containsKey()
. Это, очевидно, изменится со следующей версией guava, которая скоро будет выпущена, но, к сожалению, моя версия проекта установлена раньше.
Это ставит меня в интересное затруднительное положение. Обычно я все равно мог касаться карты, вызывая get("")
, но на самом деле я использую вычислительную карту:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.expireAfterAccess(10, TimeUnit.MINUTES)
.makeComputingMap(loadFunction);
где loadFunction
загружает MyObject
, соответствующий ключу из базы данных. Это начинает выглядеть так, будто у меня нет простого способа вытеснить до r10. Но даже возможность надежного принудительного выселения ставится под сомнение второй частью моего вопроса:
Вторая часть моего вопроса [решена]: В ответ на один из ответов на связанный вопрос, касается касания карты надежно выселить все истекшие записи? В связанном ответе Niraj Tolia указывает на другое, заявив, что выселение потенциально может обрабатываться только партиями, что означало бы, что несколько вызовов касаться карты могут потребоваться для обеспечения того, чтобы все объекты с истекшим сроком действия были выселены. Он не уточнил, однако это похоже на то, что карта разделена на сегменты на основе уровня concurrency. Предполагая, что я использовал r10, в котором a containsKey("")
вызывает выселение, будет ли это тогда для всей карты или только для одного из сегментов?
Ответ: maaartinus рассмотрел эту часть вопроса:
Остерегайтесь, что
containsKey
и другие методы чтения работают толькоpostReadCleanup
, что ничего не делает, кроме каждого 64-го вызова (см. DRAIN_THRESHOLD). Более того, похоже, что все методы очистки работают только с одним сегментом.
Итак, похоже, что вызов containsKey("")
не будет жизнеспособным исправлением, даже в r10. Это уменьшает мой вопрос до заголовка: как я могу надежно заставить выселение произойти?
Примечание.. По той причине, что моя веб-приложение заметно затронута этой проблемой, заключается в том, что когда я реализовал кэширование, я решил использовать несколько карт - по одному для каждого класса моих объектов данных. Таким образом, с этой проблемой существует вероятность того, что выполняется одна область кода, в результате чего кешируется куча объектов Foo
, а затем кеш Foo
не тронут снова в течение длительного времени, чтобы он не выселял что-нибудь. Тем временем объекты Bar
и Baz
кэшируются из других областей кода, а память еется. Я устанавливаю максимальный размер на этих картах, но это лучшая защита в лучшем случае (я предполагаю, что ее эффект немедленный - все равно нужно подтвердить это).
ОБНОВЛЕНИЕ 1: Спасибо Даррену за то, что связали соответствующие вопросы - теперь у них есть мои голоса. Таким образом, похоже, что разрешение находится в стадии разработки, но вряд ли оно будет в r10. Тем временем мой вопрос остается.
ОБНОВЛЕНИЕ 2: На данный момент я просто жду, чтобы член команды Guava дал отзыв о хаке maaartinus, и я собрал вместе (см. ответы ниже).
ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ: полученная обратная связь!