Общий кеш гугл - значение по умолчанию MaximumSize (и другие "необязательные" настройки) - хотите кеш, который использует всю "доступную" память

Я только что нашел Guava путем поиска API кеша (он идеально подходит для моих нужд). Но при чтении вики и Javadoc возник один вопрос: какие значения по умолчанию могут использовать CacheBuilder? В Javadoc говорится: "Все эти функции являются необязательными" и "Создает новый экземпляр CacheBuilder с настройками по умолчанию, включая строгие ключи, строгие значения и отсутствие какого-либо автоматического исключения".

На мой взгляд, хороший дефолт для maximumSize будет относительно Runtime.getRuntime().freeMemory();

В конце я хочу кеш, который использует память, доступную в данной системе. Поэтому мне нужна стратегия выселения, которая спрашивает, сколько freeMemory() доступно (возможно, относительно Runtime.getRuntime().maxMemory())

3 ответа

Решение

Я заставил меня подвергнуть сомнению ту же самую вещь и не мог найти что-либо в сети для этого. Так что я сделал это очень примитивное испытание. Я написал фрагмент кода, который создает LocalCache с самой простой настройкой (без максимального размера, без политик удаления, ничего) и в бесконечном цикле помещает вещи в кэш. И проверял это через VisualVm, чтобы проверить использование кучи.

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

import java.util.concurrent.TimeUnit;

public class CacheTest {
    public static void main(String[] args) {
        Cache<String, String> cache = CacheBuilder.newBuilder().build();
        int counter = 0;
        while(true){
            cache.put("key"+counter++,"value");
            System.out.println("size:"+cache.size());
        }
    }
}

Как видно из рисунка ниже, использование памяти увеличивается до максимально доступного места и становится постоянным. Я ждал несколько минут, и никакой ошибки OutOfMemoryError не произошло. Случилось так, что через несколько секунд на карту была добавлена ​​одна новая запись, поэтому в будущем, вероятно, произойдет ошибка.

Свалка

Вывод: вам не нужно устанавливать значение MaximumSize, но я предлагаю вам использовать какую-то политику выселения (expireAfterAccess или expireAfterWrite), чтобы очистить кеш и избежать OutOfMemoryError. А также, чтобы избежать снижения производительности вашего кеша.

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

Одним из вариантов является использование softValues(), но я настоятельно рекомендую против этого, так как мягкие ссылки могут действительно повредить производительности производства.

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

Код взят из класса LocalCache

      package com.google.common.cache;

@GwtCompatible(
    emulated = true
)
class LocalCache<K, V> extends AbstractMap<K, V> implements ConcurrentMap<K, V> {

      int initialCapacity = Math.min(builder.getInitialCapacity(), 1073741824);
if (this.evictsBySize() && !this.customWeigher()) {
    initialCapacity = Math.min(initialCapacity, (int)this.maxWeight);


this.initTable(this.newEntryArray(initialCapacity));

Надеюсь, это ответит на вопрос о начальном размере.

Другие вопросы по тегам