본문 바로가기

개발

JAVA HashMap 과 HashSet의 성능 비교 - 자료구조(8)

여러 자료에서 HashTable 보다는 HashMap을 권장한다. 그러면 정말 HashMap이 좋은지 데이터 추가, 조회, 삭제해보며 이 둘을 비교해보자. 간단한 테스트를 위해 키는 문자열 key + 숫자로 하였다.

성능 비교 코드는 Github에 올려 두었다.

1. 데이터 추가(put)

데이터 추가할 때 걸리는 시간을 비교하고자 하였다.

데이터를 1부터 10000000까지 10의 배수로 넣어가며 비교를 했다.

@Test
public void putTest(){
    int dataSizeLimit = 10000000;
    int dataSize = 1;

    System.out.println("put running time test\\n");
    while (dataSize <= dataSizeLimit){
        System.out.print("dataSize = "+ String.format("%10d",dataSize) );

        Map hashtable = new Hashtable();
        System.out.print(", hashTable = " + String.format("%10s", putData(hashtable, dataSize)) );

        Map hashMap = new HashMap();
        System.out.print(", hashMap = " + String.format("%10s", putData(hashMap, dataSize)) );

        dataSize *=10;
        System.out.println();
    }
}
/**
 * put running time test
 *
 * dataSize =          1, hashTable =          3, hashMap =          0
 * dataSize =         10, hashTable =          0, hashMap =          0
 * dataSize =        100, hashTable =          0, hashMap =          0
 * dataSize =       1000, hashTable =          2, hashMap =          1
 * dataSize =      10000, hashTable =         10, hashMap =          9
 * dataSize =     100000, hashTable =         61, hashMap =         31
 * dataSize =    1000000, hashTable =        339, hashMap =        302
 *
 * dataSize 가 10000000 이 넘으면 hashTable 에서 OOM 발생
 *
 * hashTable과 hashMap의 순서를 반대로 했을때
 * dataSize =          1, hashMap =          4, hashTable =          0
 * dataSize =         10, hashMap =          1, hashTable =          0
 * dataSize =        100, hashMap =          1, hashTable =          1
 * dataSize =       1000, hashMap =          4, hashTable =          2
 * dataSize =      10000, hashMap =         10, hashTable =          9
 * dataSize =     100000, hashMap =         73, hashTable =         39
 * dataSize =    1000000, hashMap =        421, hashTable =        277
 * dataSize =   10000000, hashMap =       3751
 */

private String putData(Map map, int dataSize unt) {
    AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
    for (int i = 0; i < dataSize ; i++) {
        map.put("key"+i, i);
    }
    return new AtomicLong(System.currentTimeMillis() - startTime.get()).toString();
}

속도 측면에서 이 둘의 성능 차이는 없어 보인다. 하지만 HashTable 은 10000000 이 넘으면 OutOfMemory 예외처리를 발생시킨다. 메모리 관리측면에서 HashMap이 더 좋아 보인다.

 

 

2. 데이터 조회(get)

해시의 사이즈가 달라져도 조회가 속도가 유지되는지 보고자 하였다.

조회 건수(getCount)는 100000000 인 상태에서 데이터를 1부터 10000000까지 10의 배수로 넣어가며 비교를 했다.

@Test
public void getTest(){

    int dataSizeLimit = 1000000;
    int dataSize = 1;
    int getCount = 100000000;

    System.out.println("get running time test");
    System.out.printf("get count = %d\\n\\n", getCount);
    while (dataSize <= dataSizeLimit){
        System.out.print("dataSize = "+ String.format("%10d",dataSize) );

        Map hashtable = new Hashtable();
        putData(hashtable, dataSize);
        System.out.print(", hashTable = " + String.format("%10s", getHashValue(hashtable, getCount)) );

        Map hashMap = new HashMap();
        putData(hashMap, dataSize);
        System.out.print(", hashMap = " + String.format("%10s", getHashValue(hashMap, getCount)) );

        dataSize *=10;
        System.out.println();
    }
}
/**
 * get running time test
 * get count = 100000000
 *
 * dataSize =          1, hashTable =       5962, hashMap =       4699
 * dataSize =         10, hashTable =       8385, hashMap =       5922
 * dataSize =        100, hashTable =       7280, hashMap =       5671
 * dataSize =       1000, hashTable =       7567, hashMap =       6099
 * dataSize =      10000, hashTable =       7421, hashMap =       7106
 * dataSize =     100000, hashTable =       8895, hashMap =       7870
 * dataSize =    1000000, hashTable =      11130, hashMap =       9818
 *
 *
 * hashTable과 hashMap의 순서를 반대로 했을때
 * dataSize =          1, hashMap =       4882, hashTable =       6114
 * dataSize =         10, hashMap =       5122, hashTable =       7393
 * dataSize =        100, hashMap =       5271, hashTable =       6416
 * dataSize =       1000, hashMap =       5185, hashTable =       6534
 * dataSize =      10000, hashMap =       6143, hashTable =       8745
 * dataSize =     100000, hashMap =       7551, hashTable =       9024
 * dataSize =    1000000, hashMap =       9270, hashTable =      11956
 */

private String getHashValue(Map map, int dataSize) {
    AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
    for (int i = 0; i < dataSize; i++) {
        map.get("key"+i);
    }
    return new AtomicLong(System.currentTimeMillis() - startTime.get()).toString();
}

데이터 사이즈가 증가 함에 따라 조회하는 시간이 증가하지만 그 폭이 데이터 사이즈의 증가 폭보다는 훨씬 덜하다. 조회 속도는 HashMap 이 더 빠른 것을 볼 수 있다.

 

 

3. 데이터 삭제(remove)

데이터 삭제할 때 걸리는 시간을 비교하고자 하였다.

데이터를 1부터 1000000까지 10의 배수로 넣어은 상태에서 데이터를 하나씩 삭제는 시간을 구하여 비교했다.

@Test
public void removeKeyTest(){
    int dataSizeLimit = 1000000;
    int dataSize = 1;

    System.out.println("remove running time test\\n");
    while (dataSize <= dataSizeLimit){
        System.out.print("dataSize = "+ String.format("%10d",dataSize) );

        Map hashtable = new Hashtable();
        putData(hashtable, dataSize);
        System.out.print(", hashTable = " + String.format("%10s", removeKey(hashtable, dataSize)) );

        Map hashMap = new HashMap();
        putData(hashMap, dataSize);
        System.out.print(", hashMap = " + String.format("%10s", removeKey(hashMap, dataSize)) );
        dataSize *=10;
        System.out.println();
    }
}

/**
 * remove running time test
 *
 * dataSize =          1, hashTable =          0, hashMap =          0
 * dataSize =         10, hashTable =          0, hashMap =          0
 * dataSize =        100, hashTable =          0, hashMap =          0
 * dataSize =       1000, hashTable =          2, hashMap =          1
 * dataSize =      10000, hashTable =          5, hashMap =          4
 * dataSize =     100000, hashTable =         20, hashMap =         17
 * dataSize =    1000000, hashTable =        169, hashMap =        156
 *
 * hashTable과 hashMap의 순서를 반대로 했을때
 * dataSize =          1, hashMap =          1, hashTable =          0
 * dataSize =         10, hashMap =          0, hashTable =          0
 * dataSize =        100, hashMap =          0, hashTable =          1
 * dataSize =       1000, hashMap =          2, hashTable =          1
 * dataSize =      10000, hashMap =          7, hashTable =          4
 * dataSize =     100000, hashMap =         18, hashTable =         25
 * dataSize =    1000000, hashMap =        167, hashTable =        270
 */

private String removeKey(Map map, int dataSize) {
    AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
    for (int i = 0; i < dataSize; i++) {
        map.remove("key"+i);
    }
    return new AtomicLong(System.currentTimeMillis() - startTime.get()).toString();
}

삭제 속도가 HashMap이 더 좋은 것을 볼 수 있다.

 

 


자료구조 시리즈

1. 자료구조의 종류와 개념 - 자료구조(1)

2. JAVA ArrayList - 자료구조(2)

3. JAVA LinkedList - 자료구조(3) 

4. JAVA ArrayList와 LinkedList 성능 비교 - 자료구조(4)

5. JAVA Queue 그리고 offer, poll , peek - 자료구조(5)

6. JAVA 왜 Stack 은 Array로, Queue는 LinkedList로 구현 했을까? - 자료구조(6)

7. JAVA Hash 그리고 HashMap 과 HashTable - 자료구조(7)

8. JAVA HashMap 과 HashSet의 성능 비교 - 자료구조(8)

9. JAVA HashMap의 용량은 왜 2의 거듭제곱일까? - 자료구조(9)