2012-06-19 3 views
10

"고전적인"HashMap과 비교하여 ConcurrentHashMap의 메모리 오버 헤드를 아는 사람이 있습니까?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(); 
} 

1 백만 항목의 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. 

8MB의 메모리 비용은 약 5 센트입니다.

+0

메모리 사용량을 얼마나 신뢰할 수 있습니까? – assylias

+0

스레드 로컬 할당을 사용하는 지점을 설명 할 수 있습니까? 감사! – assylias

+0

Java 5 또는 HotSpot 또는 OpenJDK 이외의 다른 JVM에서는 다를 수 있지만 크게 다를 경우 놀랄 것입니다. 차이는 32 비트 JVM에서 더 작을 수 있습니다. –

2

나는이 질문의 전제를 이해하지 못한다. 동시성이 필요하거나 그렇지 않다.

그러나 this link에 따르면 빈 ConcurrentHashMap의 메모리 풋 프린트는 1700 바이트입니다. 읽기/쓰기 액세스가 필요한 여러 스레드가있는 경우 ConcurrentHashMap을 사용하는 것이 좋지만 읽기 액세스가 필요한 많은 스레드가 있지만 쓰기가있는 스레드가 많은 경우 Hashtable을 사용하는 것이 좋습니다.

+0

링크가 너무 오래되어 관련성이 없습니다. 실제로이 기사는 Java 7 이전에 발표되었으며 (2004 년 4 월 28 일) Java 7 구현이 변경되었을 가능성이 있습니다. 더구나, 당신의 대답은 삽입을 요구하기 때문에 불완전합니다 (하나가 있습니다). – Maxime

+2

@Maxime 구현은 아마도 그렇게 많이 변경되지는 않았지만 어떤 경우에는 데이터를 찾는 데 사용한 메소드를 설명합니다. 약간의 연구 결과에 따르면 아직 다른 사람이 해본 적이 없다고합니다. – purtip31

4

ConcurrentHashMap은 건설 및 삽입시 모두 HashMap보다 훨씬 많은 메모리를 사용하지 않습니다. 초기화 데이터

ConcurrentHashMap에서

은 HashMap과 같이 메모리의 거의 같은 양 사용하고, 별도의 부기 변수 잠금 커플 약간 이상일 수있다.

초기화 중에 ConcurrentHashMap은 16 개의 세그먼트를 만들어 키 - 값을 저장하며 각 세그먼트는 HashMap과 동일합니다.

각 세그먼트의 초기 용량/크기는 전체 초기 용량의 1/16입니다. 따라서 본질적으로 ConcurrentHashMap은 하나의 HashMap에 해당하는 16 개의 작은 HashMaps를 생성합니다. 각 세그먼트에는 자체 잠금 및 장부 보관 변수 (개수, 임계 값 등)가 있습니다. 이는 여분의 메모리 오버 헤드입니다.

당신은 ConcurrentHashMap의 concurrencyLevel 매개 변수에 적절한 값을 전달하여 ConcurrentHashMap에 의해 만들어진 세그먼트의 수를 제어 할 수 있습니다. 이 값이 작 으면 사용되는 공간은 적지 만 많은 수의 스레드가 맵을 업데이트하면 더 많은 경합이 발생합니다. 이 값이 높을수록 세그먼트가 더 많이 생성되지만 병렬 업데이트의 성능은 더 빠릅니다. 참고 : concurrencyLevel 매개 변수의 값이 현저히 높으면 공간과 시간에 모두 영향을줍니다.

메모리의이 작은 오버 헤드는 개발자가 동시성에 대한 대가로 기꺼이 받아 들일 수있는 것입니다. 삽입 세그먼트가 작성 얻을

에서

, 그 세그먼트의 크기가 증가됩니다. 크기를 늘리는 정책은 HashMap과 동일합니다. loadfactor 매개 변수는 세그먼트의 크기를 늘릴시기를 결정합니다. 채워지는 세그먼트 만 증가합니다.다시 한번, 메모리 오버 헤드는 HashMap과 거의 같습니다.

전체적으로 ConcurrentHashMapHashMap보다 훨씬 많은 메모리를 사용하지 않지만, ConcurrentHashMap에서 사용되는 모든 추가 바이트를 측정하는 것은 실제로 어렵습니다.