Принуждение освобождения большого кэша возражает в Java

Я использую большое (миллионы) записей hashmap к значениям кэша, необходимым алгоритму, ключ является комбинацией двух объектов как длинное. Так как это растет непрерывно (потому что вводят изменения карты, таким образом, старые больше не нужны), было бы хорошо быть в состоянии вызвать стирание всех данных, содержавшихся в нем и запуститься снова во время выполнения, там способ сделать эффективно в Java?

Я имею в виду, освобождают связанную память (о 1-1.5gb из hashmap) и перезапуск от пустого hashmap..

10
задан Jack 9 March 2010 в 02:56
поделиться

6 ответов

Вы можете вызвать HashMap.clear () . Это удалит все данные. Обратите внимание, что при этом будут отброшены только все записи, но внутренний массив, используемый для хранения записей, будет иметь тот же размер (а не сжиматься до начальной емкости). Если вам также необходимо это устранить, самым простым способом было бы отказаться от всей HashMap и заменить ее новым экземпляром. Это, конечно, работает только в том случае, если вы контролируете, у кого есть указатель на карту.

Что касается освобождения памяти, вы должны позволить сборщику мусора делать свою работу.

Ваши ценности тоже Лонг? В этом случае вам может потребоваться более эффективная (с точки зрения памяти) реализация , чем обычная HashMap, такая как TLongLongHashMap из библиотеки GNU Trove . Это должно сэкономить много памяти.

14
ответ дан 3 December 2019 в 14:33
поделиться

Похоже, вам нужна WeakHashMap вместо:

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

Я не знаю, как это работает с Long в качестве ключей. Также это может быть интересно:

WeakHashMap не является кешем! Общие сведения о WeakReference и SoftReference

13
ответ дан 3 December 2019 в 14:33
поделиться

Вы видели WeakHashMap ?

0
ответ дан 3 December 2019 в 14:33
поделиться

Для кэша с учетом памяти вы можете использовать коллекции Apache Commons , в частности их класс org.apache.commons.collections.map.ReferenceMap . Специальная операция Java - это программный справочник . Java предоставляет WeakHashMap для слабых ссылок, но слабые ссылки - это не то, что вам нужно для кеша. Java не предоставляет SoftHashMap , но ReferenceMap из Apache Commons может быть работоспособной заменой.

Осведомленность о мягких ссылках в памяти несколько грубая и негибкая. Вы можете поиграть с некоторыми параметрами Java, чтобы как-то их настроить, особенно с значением -XX: SoftRefLRUPolicyMSPerMB , которое выражает (в миллисекундах), как долго значения с мягкими ссылками хранятся в памяти (когда они перестают быть доступными напрямую). ). Например, с этим:

java -XX:SoftRefLRUPolicyMSPerMB=2500

тогда JVM будет пытаться сохранить кэшированное значение на 2,5 секунды дольше, чем это было бы с WeakHashMap .

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

Чередование между «полным кешем» и «пустым кешем» также может считаться несколько грубым, поэтому вы можете поддерживать несколько карт. Например, у вас есть десять карт.Когда вы ищете кэшированное значение, вы смотрите на все карты, но когда у вас есть значение, вы помещаете его только в первую карту. Когда вы хотите смыть, вы вращаете карты: первая карта становится второй, вторая становится третьей и так далее, вплоть до десятой карты, которая отбрасывается. Создается новая свежая первая карта. Это будет выглядеть так:

import java.util.*;

public class Cache {

    private static final int MAX_SIZE = 500000;

    private Map[] backend;
    private int size = 0;

    public Cache(int n)
    {
        backend = new Map[n];
        for (int i = 0; i < n; i ++)
            backend[i] = new HashMap();
    }

    public int size()
    {
        return size;
    }

    public Object get(Object key)
    {
        for (Map m : backend) {
            if (m.containsKey(key))
                return m.get(key);
        }
        return null;
    }

    public Object put(Object key, Object value)
    {
        if (backend[0].containsKey(key))
            return backend[0].put(key, value);
        int n = backend.length;
        for (int i = 1; i < n; i ++) {
            Map m = backend[i];
            if (m.containsKey(key)) {
                Object old = m.remove(key);
                backend[0].put(key, value);
                return old;
            }
        }
        backend[0].put(key, value);
        size ++;
        while (size > MAX_SIZE) {
            size -= backend[n - 1].size();
            System.arraycopy(backend, 0, backend, 1, n - 1);
            backend[0] = new HashMap();
        }
        return null;
    }
}

Приведенный выше код полностью не протестирован и должен быть расширен с помощью универсальных шаблонов. Однако он иллюстрирует основные идеи: все карты проверяются при чтении ( get () ), все новые значения переходят в первую карту, общий размер сохраняется, и когда размер превышает заданный предел, карты повернуты. Обратите внимание, что при установке нового значения для известного ключа применяется особый подход. Кроме того, в этой версии ничего особенного не делается при нахождении кэшированного значения, но мы можем «омолодить» полученное кэшированное значение: после get () , когда значение найдено, но не в первой карте, оно может быть перемещен на первую карту. Таким образом, часто используемые значения останутся в кэше навсегда.

3
ответ дан 3 December 2019 в 14:33
поделиться

Очистить hashmap:

hashmap.clear();

Затем принудительно запустить сборщик мусора:

Runtime.getRuntime().gc();

Это страница Javadoc для Runtime.gc().

3
ответ дан 3 December 2019 в 14:33
поделиться

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

Только мои 2 цента :)

0
ответ дан 3 December 2019 в 14:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: