Подтвердить что ты не робот

Накладные расходы ConcurrentHashMap

Знает ли кто-нибудь, что является издержками памяти ConcurrentHashMap (по сравнению с "классическим" HashMap)?

  • При построении?
  • При вставке элемента?
4b9b3361

Ответ 1

Если вы запускаете следующее с -XX:-UseTLAB -XX:NewSize=900m -mx1g в 64-разрядной JVM.

public static void main(String... args) throws NoSuchMethodException, IllegalAccessException {
    for (int i = 0; i < 4; i++) {
        long used1 = usedMemory();
        populate(new HashMap());
        long used2 = usedMemory();
        populate(new ConcurrentHashMap());
        long used3 = usedMemory();
        System.out.println("The ratio of used memory is " + (double) (used3 - used2) / (used2 - used1));
        System.out.println("For an extra " + ((used3 - used2) - (used2 - used1)) / 1000000 + " bytes per entry was used.");
    }
}

private static void populate(Map map) {
    for (Integer i = 0; i < 1000000; i++)
        map.put(i, i);
}

private static long usedMemory() {
    return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}

вы получаете с Java 6 и 7 за миллион записей.

The ratio of used memory is 1.1291128466982379
For an extra 8 bytes per entry was used.
The ratio of used memory is 1.1292086928728067
For an extra 8 bytes per entry was used.
The ratio of used memory is 1.1292086928728067
For an extra 8 bytes per entry was used.
The ratio of used memory is 1.1292086928728067
For an extra 8 bytes per entry was used.

Восемь мегабайт памяти стоит около 5 центов.

Ответ 2

ConcurrentHashMap не использует значительно большую память, чем HashMap, как при построении, так и при вставке.

При инциализации

ConcurrentHashMap использует почти тот же объем памяти, что и HashMap, может быть немного больше для пары дополнительных учетных переменных и блокировок.

Во время инициализации ConcurrentHashMap создает 16 сегментов для хранения значений ключа, каждый сегмент эквивалентен HashMap.

Внутренняя емкость/размер каждого сегмента составляет 1/16 от общей начальной емкости. Таким образом, по существу, ConcurrentHashMap создает 16 маленьких HashMaps, эквивалентных одному HashMap. Каждый сегмент имеет собственную блокировку и пару переменных бухгалтерского учета (счетчик, порог и т.д.), Это дополнительные издержки памяти.

Вы можете управлять количеством сегментов, созданных с помощью ConcurrentHashMap, передав соответствующее значение параметру concurrencyLevel в ConcurrentHashMap. Чем меньше это значение, тем меньше места будет использовано, но больше конфликтов, когда большое количество потоков обновит карту. Чем выше это значение, тем больше будет создано сегментов, но производительность параллельных обновлений будет быстрее. Примечание. Значительно более высокое значение параметра concurrencyLevel влияет как на пространство, так и на время.

Эти небольшие накладные расходы в памяти - это то, что разработчик готов принять в обмен на concurrency.

При вставке

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

В целом ConcurrentHashMap не использует значительно больше памяти, чем HashMap, но очень сложно измерить каждый дополнительный байт, используемый ConcurrentHashMap.

Ответ 3

Я действительно не понимаю предпосылки вопроса - вам нужен concurrency, или вы этого не делаете.

Однако, согласно эта ссылка, объем памяти пустой ConcurrentHashMap составляет 1700 байт. Он рекомендует использовать ConcurrentHashMap, если у вас есть несколько потоков, которым нужен доступ для чтения/записи, но Hashtable, если у вас много потоков, которым нужен доступ для чтения, но один с записью.