EDIT: я реорганизовал этот вопрос, чтобы отразить новую информацию, которая с тех пор стала доступной.
Этот вопрос основан на ответах на вопрос Вилиама об использовании Google 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()
. Это, по-видимому, изменится со следующей версией гуавы, которая скоро будет выпущена, но, к сожалению, выпуск моего проекта назначен раньше.
Это ставит меня в интересное затруднительное положение. Обычно я все еще мог коснуться карты, вызвав get("")
, но на самом деле я использую вычислительную карту:
ConcurrentMap<String, MyObject> cache = new MapMaker()
.expireAfterAccess(10, TimeUnit.MINUTES)
.makeComputingMap(loadFunction);
где loadFunction
загружает MyObject
, соответствующий ключу из базы данных. Похоже, у меня нет простого способа принудительно выселить до r10. Но даже возможность надежного принудительного выселения ставится под сомнение второй частью моего вопроса:
Вторая часть моего вопроса [решена]: В ответ на один из ответов на связанный вопрос, удалит ли прикосновение к карте все записи с истекшим сроком действия? В связанном ответе Niraj Tolia указано обратное, говоря, что выселение потенциально обрабатывается только пакетами, что означает несколько вызовов чтобы коснуться карты, может потребоваться, чтобы убедиться, что все объекты с истекшим сроком действия были выселены. Он не уточнил, однако это, похоже, связано с разделением карты на сегменты в зависимости от уровня параллелизма. Предполагая, что я использовал r10, в котором containsKey("")
вызывает выселение, будет ли это тогда для всей карты или только для одного из сегментов?
Ответ: maaartinus затронул эту часть вопроса:
Помните, что
containsKey
и другие методы чтения запускают толькоpostReadCleanup
, который ничего не делает, кроме как при каждом 64-м вызове (см. DRAIN_THRESHOLD). Более того, похоже, что все методы очистки работают только с одним сегментом.
Таким образом, похоже, что вызов containsKey("")
не будет жизнеспособным решением даже в r10. Это сводит мой вопрос к заголовку: Как я могу надежно вызвать выселение?
Примечание. Одна из причин, по которой эта проблема заметно влияет на мое веб-приложение, заключается в том, что при реализации кэширования я решил использовать несколько карт — по одной для каждого класса моих объектов данных. Таким образом, с этой проблемой существует вероятность того, что одна область кода выполняется, что приводит к кэшированию группы объектов Foo
, а затем кеш Foo
не трогается снова в течение длительного времени, поэтому он ничего не вытесняет. Тем временем объекты Bar
и Baz
кэшируются из других областей кода, и память потребляется. Я устанавливаю максимальный размер на этих картах, но это в лучшем случае ненадежная защита (я предполагаю, что ее эффект будет немедленным — все еще нужно это подтвердить).
ОБНОВЛЕНИЕ 1: Спасибо Даррену за ссылку на соответствующие вопросы — теперь у них есть мои голоса. Так что похоже, что разрешение находится в стадии разработки, но вряд ли будет в r10. А пока мой вопрос остается.
ОБНОВЛЕНИЕ 2: На данный момент я просто жду, когда член команды Guava даст отзыв о взломе, который мы с maaartinus собрали (см. ответы ниже).
ПОСЛЕДНЕЕ ОБНОВЛЕНИЕ: получен отзыв!