2012-06-19 5 views
10

ConcurrentHashMapのメモリオーバーヘッドは何ですか(「クラシック」HashMapと比較して)ConcurrentHashMapメモリオーバーヘッド

  • 建設中ですか?
  • 要素の挿入時に?
+0

ConcurrentHashMapを多数作成するのは意味がありません。コア数が限られているだけです。少数のCHMのオーバーヘッドは1セント未満のメモリになる可能性があります。 –

+0

@PeterLawrey私は本当にあなたのポイントを取得していません。 「大量のConcurrentHashMapを作成するのは無駄です。彼らはまだオーバーヘッドを持っています。さらに、同時に多くのCHMを持つことは明らかに奇妙であっても、短命オブジェクトが構築時に同時にハッシュマップを作成することを容易に想像することができます(DB指向のソフトウェアの結合演算子を考えてみましょう)。 – Maxime

+0

同時収集を使用する理由は、収集数よりもコア数が多いためです。コアよりもコレクションの数が多い場合は、同時にアクセスする可能性はほとんどありません。 –

答えて

6

64ビットJVM上で-XX:-UseTLAB -XX:NewSize=900m -mx1gを使用して以下を実行する場合。

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セントです。

+0

メモリ使用量の測定はどれくらい信頼できますか? – assylias

+0

スレッドローカル割り当ての使用のポイントを説明できますか?ありがとう! – assylias

+0

Java 5やその他のJVMではHotSpotやOpenJDKとは異なるかもしれませんが、大きく異なる場合は驚くでしょう。この違いは、32ビットのJVMでは小さくなる可能性があります。 –

2

私は実際に質問の前提を理解していません。あなたは同時性が必要なのか、そうでないのでしょうか。

しかし、this linkによると、空きのメモリフットプリントConcurrentHashMapは1700バイトです。読み取り/書き込みアクセスが必要な複数のスレッドがある場合はConcurrentHashMapを使用することをお勧めします。ただし、読み取りアクセスが必要なスレッドが多数ある場合はHashtableが必要です。

+0

リンクが古すぎて関連性がありません。確かに、この記事はJava 7より前に公開され(04/28/2012)、実装はおそらく変更されています。また、私は挿入を求めるので、あなたの答えは不完全です(1つあります)。 – Maxime

+2

@ Maxime Implementationはあまり変更されていない可能性がありますが、いずれの場合でもデータを見つけるために使用した方法について説明しています。研究のビットは、誰もまだそれをしていないことを示しています。 – purtip31

4

ConcurrentHashMapは、構成時および挿入時の両方で、HashMapよりも大幅に多くのメモリを使用しません。使う初期

ConcurrentHashMap

は、HashMapのようなメモリのほぼ同じ量を使用して、余分な簿記の変数とロックのカップルのために少し以上であってもよいです。

初期化中、ConcurrentHashMapは16個のセグメントを作成してキー値を格納します。各セグメントはHashMapに相当します。

各セグメントの初期容量/サイズは、初期容量全体の1/16です。したがって、本質的にConcurrentHashMapは、1つのHashMapに相当する16の小さなHashMapsを作成します。各セグメントには独自のロックとブックキーピング変数(カウント、しきい値など)がありますが、これは余分なメモリオーバーヘッドです。

あなたはConcurrentHashMapのconcurrencyLevelパラメータに適切な値を渡すことでConcurrentHashMapによって作成されたセグメントの数を制御することができます。この値が小さければ、使用されるスペースは少なくなりますが、スレッド数が多い場合は競合が増えます。この値が高いほど、セグメントが多く作成されますが、並列更新のパフォーマンスは向上します。注:concurrencyLevelパラメーターの値が大幅に高い場合は、スペースと時間の両方に影響します。

この小さなメモリオーバーヘッドは、開発者が並行処理と引き換えに受け入れるものです。挿入

セグメントをいっぱいにすると、そのセグメントのサイズが大きくなります。サイズを大きくするポリシーは、HashMapと同じです。 loadfactorパラメータは、セグメントのサイズを増やすタイミングを決定します。塗りつぶされたセグメントのみが増加することに注意してください。もう一度、メモリオーバーヘッドはHashMapとほとんど同じです。

全体としてConcurrentHashMapは、HashMapよりも大幅に多くのメモリを使用していませんが、ConcurrentHashMapで使用されているすべての余分なバイトを測定することは本当に難しいです。

関連する問題