Map系クラスのメモリ使用量の違い
唐突に、HashMap、LinkedHashMap、TreeMapのメモリ使用量の違いを測ってみようと思った。
ただ、メモリ使用量、というよりは、いくつのkey-valueを保持できるか、というところに力点を置いた結果の示し方をする。
検証用コードはこんな感じ。
import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; public class Main { private static NumberFormat ID_GEN_30 = new DecimalFormat( "000000000000000000000000000000"); private static NumberFormat ID_GEN_60 = new DecimalFormat( "000000000000000000000000000000000000000000000000000000000000"); private static NumberFormat ID_GEN_120 = new DecimalFormat( "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); /** * @param args */ public static void main(String[] args) { Map map; if (System.getProperty("map").equals("linkedHash")) { map = new LinkedHashMap(); } else if (System.getProperty("map").equals("tree")) { map = new TreeMap(); } else { map = new HashMap(); } long id = 0; try { for (; true; ++id) { if (id % 10000 == 0) { System.out.println(id); dumpMemoryUsage(); } Object idObj = generate(id); map.put(idObj, idObj); } } finally { map.clear(); System.out.print(id); System.err.print(id); } } private static Object generate(long id) { if (System.getProperty("generator").equals("string30")) { return ID_GEN_30.format(id); } else if (System.getProperty("generator").equals("string60")) { return ID_GEN_60.format(id); } else if (System.getProperty("generator").equals("string120")) { return ID_GEN_120.format(id); } else { return new Long(id); } } private static void dumpMemoryUsage() { Runtime rt = Runtime.getRuntime(); long max = rt.maxMemory(); long total = rt.totalMemory(); long free = rt.freeMemory(); long used = (total - free); System.out.println(" maxMemory = " + (max / 1024.0 / 1024)); System.out.println("totalMemory = " + (total / 1024.0 / 1024)); System.out.println(" freeMemory = " + (free / 1024.0 / 1024)); System.out.println(" usedMemory = " + (used / 1024.0 / 1024)); } }
実行時のプロパティ値によって、検証内容を切り替えられるようにしている。
また、一応、メモリ使用状況も出力するようにしているが、今回は省略。確認されたい方はご自身で。
で、これを次のようなバッチを作って実行する。
@ECHO OFF SETLOCAL PUSHD %~dp0 CALL :TEST 1 j2sdk1.4.2_18 CALL :TEST 2 j2sdk1.4.2_18 CALL :TEST 3 j2sdk1.4.2_18 CALL :TEST 1 jdk1.5.0_11 CALL :TEST 2 jdk1.5.0_11 CALL :TEST 3 jdk1.5.0_11 CALL :TEST 1 jdk1.6.0_01 CALL :TEST 2 jdk1.6.0_01 CALL :TEST 3 jdk1.6.0_01 GOTO END :TEST SETLOCAL SET JAVA_HOME=C:\%2 SET PATH=%JAVA_HOME%\bin;%PATH% java -version SET LOGDIR=result-%1-%2 MKDIR %LOGDIR% CALL :RUN hash string30 %LOGDIR% CALL :RUN linkedHash string30 %LOGDIR% CALL :RUN tree string30 %LOGDIR% CALL :RUN hash string60 %LOGDIR% CALL :RUN linkedHash string60 %LOGDIR% CALL :RUN tree string60 %LOGDIR% CALL :RUN hash string120 %LOGDIR% CALL :RUN linkedHash string120 %LOGDIR% CALL :RUN tree string120 %LOGDIR% CALL :RUN hash long %LOGDIR% CALL :RUN linkedHash long %LOGDIR% CALL :RUN tree long %LOGDIR% ENDLOCAL EXIT /B :RUN java -Dmap=%1 -Dgenerator=%2 -classpath classes Main > %3\result-%2-%1.txt EXIT /B :END ENDLOCAL
これによって得られた各結果を集計するためのスクリプト。
#! /bin/bash for v in j2sdk1.4.2_18 jdk1.5.0_11 jdk1.6.0_01 ; do for f in `ls result-1-${v}` ; do echo -n "${f},${v}," for d in result-*-${v} ; do tail -1 ${d}/${f} echo -n ',' done echo done done |\ awk -F ',' ' BEGIN { } { generator_map = $1; version = $2; val1 = $3; val2 = $4; val3 = $5; gsub(/^result[-]/, "", generator_map); gsub(/[.]txt$/, "", generator_map); split(generator_map, ary, "-"); generator = ary[1]; map = ary[2]; avg = (val1 + val2 + val3) / 3.0; if (_generator != generator || _version != version) { base = avg; } printf("%-13s %-10s %-10s %12d %12d %12d %16.3f %6.1f%%\n", version, generator, map, val1, val2, val3, avg, 100 * (avg / base)); _generator = generator; _version = version; }'
そして、集計結果。
バージョン | オブジェクト | Map | 1回目 | 2回目 | 3回目 | 平均 | 比率(hashを100%) |
j2sdk1.4.2_18 | long | hash | 1453529 | 1453529 | 1453529 | 1453529.000 | 100.0% |
linkedHash | 1211273 | 1211273 | 1211273 | 1211273.000 | 83.3% | ||
tree | 1386037 | 1386037 | 1386037 | 1386037.000 | 95.4% | ||
string30 | hash | 486989 | 486989 | 486989 | 486989.000 | 100.0% | |
linkedHash | 458342 | 458342 | 458342 | 458342.000 | 94.1% | ||
tree | 489183 | 489183 | 489183 | 489183.000 | 100.5% | ||
string60 | hash | 322158 | 322158 | 322158 | 322158.000 | 100.0% | |
linkedHash | 309767 | 309767 | 309767 | 309767.000 | 96.2% | ||
tree | 319850 | 319850 | 319850 | 319850.000 | 99.3% | ||
string120 | hash | 190349 | 190349 | 190349 | 190349.000 | 100.0% | |
linkedHash | 186022 | 186022 | 186022 | 186022.000 | 97.7% | ||
tree | 189002 | 189002 | 189002 | 189002.000 | 99.3% | ||
jdk1.5.0_11 | long | hash | 1452091 | 1452091 | 1452091 | 1452091.000 | 100.0% |
linkedHash | 1210075 | 1210075 | 1210075 | 1210075.000 | 83.3% | ||
tree | 1384839 | 1384839 | 1384839 | 1384839.000 | 95.4% | ||
string30 | hash | 518975 | 518975 | 518975 | 518975.000 | 100.0% | |
linkedHash | 486539 | 486539 | 486539 | 486539.000 | 93.7% | ||
tree | 519307 | 519307 | 519307 | 519307.000 | 100.1% | ||
string60 | hash | 349859 | 349859 | 349859 | 349859.000 | 100.0% | |
linkedHash | 335281 | 335281 | 335281 | 335281.000 | 95.8% | ||
tree | 346204 | 346204 | 346204 | 346204.000 | 99.0% | ||
string120 | hash | 211756 | 211756 | 211756 | 211756.000 | 100.0% | |
linkedHash | 206326 | 206326 | 206326 | 206326.000 | 97.4% | ||
tree | 213048 | 213048 | 213048 | 213048.000 | 100.6% | ||
jdk1.6.0_01 | long | hash | 1451522 | 1451523 | 1451522 | 1451522.333 | 100.0% |
linkedHash | 1209601 | 1209601 | 1209601 | 1209601.000 | 83.3% | ||
tree | 1384365 | 1384365 | 1384365 | 1384365.000 | 95.4% | ||
string30 | hash | 518785 | 518785 | 518785 | 518785.000 | 100.0% | |
linkedHash | 486361 | 486361 | 486361 | 486361.000 | 93.8% | ||
tree | 519129 | 519129 | 519129 | 519129.000 | 100.1% | ||
string60 | hash | 349735 | 349735 | 349735 | 349735.000 | 100.0% | |
linkedHash | 335163 | 335163 | 335163 | 335163.000 | 95.8% | ||
tree | 346086 | 346086 | 346086 | 346086.000 | 99.0% | ||
string120 | hash | 211681 | 211681 | 211681 | 211681.000 | 100.0% | |
linkedHash | 206253 | 206253 | 206253 | 206253.000 | 97.4% | ||
tree | 212975 | 212975 | 212975 | 212975.000 | 100.6% |
まぁ、LinkedHashMapはHashMapよりメモリをいくらか余分に必要とするんだということを再確認できた、と(謎)
TreeMapで100%を超えている部分があったのはちょっと意外な感じ。