ConcurrentHashMap内存开销

Max*_*ime 10 java hashmap concurrenthashmap memory-profiling

有人知道ConcurrentHashMap的内存开销是什么(与"经典"HashMap相比)?

  • 在施工?
  • 在插入元素?

Pet*_*rey 9

如果-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();
}
Run Code Online (Sandbox Code Playgroud)

你可以使用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.
Run Code Online (Sandbox Code Playgroud)

8 MB的内存成本约为5美分.

  • 我特意将它们关闭,因为虽然它们通过允许多线程对象分配来提高效率,但它们使得"freeMemory()"不太准确. (3认同)
  • 带有空映射的代码显示ConcurrentHashMap的初始大小比HashMap高96个字节(224对128个字节).与其他答案中提到的1,700字节数字相差甚远. (2认同)

spe*_*mal 5

ConcurrentHashMapHashMap在构造和插入时,不会使用比 多得多的内存。

初始化时

ConcurrentHashMap使用与 HashMap 几乎相同的内存量,对于几个额外的簿记变量和锁可能会稍微多一些。

初始化时,ConcurrentHashMap创建16个Segment来存储key-value,每个Segment相当于一个HashMap。

每个Segment的初始容量/大小是总体初始容量的1/16。所以本质上,ConcurrentHashMap创建了16个小HashMap相当于1个HashMap。每个段都有自己的锁和几个簿记变量(计数、阈值等),这是额外的内存开销。

ConcurrentHashMap您可以通过将适当的值传递给concurrencyLevel参数来控制创建的 Segment 数量ConcurrentHashMap。该值越小,则使用的空间越少,但当大量线程更新 Map 时,争用会更多。该值越高,将创建更多的段,但并行更新的性能会更快。注意: concurrencyLevel参数的值明显较高,会影响空间和时间。

这种小的内存开销是开发人员愿意接受的,以换取并发性。

插入时

当段被填满时,该段的大小将增加。增加大小的策略与HashMap相同。loadfactor参数决定何时增加 Segment 的大小。请注意,填充的段将会增加。再次强调,内存开销与 HashMap 几乎相同。

总体而言,ConcurrentHashMap使用的内存并不比 多得多HashMap,但确实很难测量 所使用的每个额外字节ConcurrentHashMap