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();
}
100 万エントリの 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.
8 MB のメモリのコストは約 5 セントです。
ConcurrentHashMap
HashMap
は、構築時と挿入時の両方で、よりも大幅に多くのメモリを使用しません。
初期化時
ConcurrentHashMap
HashMap とほぼ同じ量のメモリを使用しますが、いくつかの追加の簿記変数とロックの場合はわずかに多くなる場合があります。
初期化中に、ConcurrentHashMap
16 個のセグメントを作成してキー値を格納します。各セグメントは HashMap に相当します。
各セグメントの初期容量/サイズは、全体の初期容量の 1/16 です。したがって、本質的には、 ConcurrentHashMap
1 つの HashMap に相当する 16 個の小さな HashMap を作成します。各セグメントには独自のロックといくつかの簿記変数 (カウント、しきい値など) があり、これは追加のメモリ オーバーヘッドです。
のconcurrencyLevelパラメータにConcurrentHashMap
適切な値を渡すことで、作成されるセグメントの数を制御できます。この値が小さいほど、使用されるスペースは少なくなりますが、多数のスレッドがマップを更新するときの競合が多くなります。この値が大きいほど、より多くのセグメントが作成されますが、並列更新のパフォーマンスは高速になります。注: concurrencyLevelパラメーターの値を大幅に高くすると、スペースと時間の両方に影響します。ConcurrentHashMap
このメモリのわずかなオーバーヘッドは、並行性と引き換えに開発者が喜んで受け入れるものです。
挿入時
セグメントがいっぱいになると、そのセグメントのサイズが増加します。サイズを大きくするポリシーは HashMap と同じです。loadfactorパラメータは、セグメントのサイズをいつ増やすかを決定します。満たされているセグメントが増加することにのみ注意してください。繰り返しになりますが、メモリ オーバーヘッドは HashMap とほぼ同じです。
全体として、ConcurrentHashMap
は よりも大幅に多くのメモリを使用しませんがHashMap
、 が使用するすべての余分なバイトを測定するのは非常に困難ConcurrentHashMap
です。
質問の前提がよくわかりません-同時実行が必要かどうか。
ただし、このリンクによると、空のメモリ フットプリントConcurrentHashMap
は 1700 バイトです。ConcurrentHashMap
読み取り/書き込みアクセスが必要なスレッドが複数ある場合はを使用することをお勧めしますが、Hashtable
読み取りアクセスが必要なスレッドが多数あり、書き込みアクセスが必要なスレッドがある場合は を使用することをお勧めします。