Знает ли кто-нибудь, что является издержками памяти ConcurrentHashMap (по сравнению с "классическим" HashMap)?
- При построении?
- При вставке элемента?
Знает ли кто-нибудь, что является издержками памяти ConcurrentHashMap (по сравнению с "классическим" HashMap)?
Если вы запускаете следующее с -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 центов.
ConcurrentHashMap
не использует значительно большую память, чем HashMap
, как при построении, так и при вставке.
При инциализации
ConcurrentHashMap
использует почти тот же объем памяти, что и HashMap, может быть немного больше для пары дополнительных учетных переменных и блокировок.
Во время инициализации ConcurrentHashMap
создает 16 сегментов для хранения значений ключа, каждый сегмент эквивалентен HashMap.
Внутренняя емкость/размер каждого сегмента составляет 1/16 от общей начальной емкости. Таким образом, по существу, ConcurrentHashMap
создает 16 маленьких HashMaps, эквивалентных одному HashMap. Каждый сегмент имеет собственную блокировку и пару переменных бухгалтерского учета (счетчик, порог и т.д.), Это дополнительные издержки памяти.
Вы можете управлять количеством сегментов, созданных с помощью ConcurrentHashMap
, передав соответствующее значение параметру concurrencyLevel в ConcurrentHashMap
. Чем меньше это значение, тем меньше места будет использовано, но больше конфликтов, когда большое количество потоков обновит карту. Чем выше это значение, тем больше будет создано сегментов, но производительность параллельных обновлений будет быстрее. Примечание. Значительно более высокое значение параметра concurrencyLevel влияет как на пространство, так и на время.
Эти небольшие накладные расходы в памяти - это то, что разработчик готов принять в обмен на concurrency.
При вставке
Когда сегменты будут заполнены, размер этого сегмента будет увеличен. Политика увеличения размера аналогична политике HashMap. параметр loadfactor решает, когда увеличить размер сегмента. Обратите внимание только на то, что сегмент, который будет заполнен, будет увеличен. Еще раз, накладные расходы памяти почти такие же, как HashMap.
В целом ConcurrentHashMap
не использует значительно больше памяти, чем HashMap
, но очень сложно измерить каждый дополнительный байт, используемый ConcurrentHashMap
.
Я действительно не понимаю предпосылки вопроса - вам нужен concurrency, или вы этого не делаете.
Однако, согласно эта ссылка, объем памяти пустой ConcurrentHashMap
составляет 1700 байт. Он рекомендует использовать ConcurrentHashMap
, если у вас есть несколько потоков, которым нужен доступ для чтения/записи, но Hashtable
, если у вас много потоков, которым нужен доступ для чтения, но один с записью.