列挙型専用のSet - java.util.EnumSet
EnumMapと同じようなことを、EnumSetに対してもやってみた。
列挙型はEnumMapの場合と同じだが、再掲。
enum A {
A_1,
A_2,
A_3;
}
次にテスト用のクラス。ただ、EnumSetクラスにはpublicなコンストラクタがなく、代わりに要素なしのEnumSetオブジェクトを生成するEnumSet#noneOf(Class)メソッドを使用する。
import java.util.EnumSet; import java.util.List; import java.util.Set; public class EnumSetTester { public void test(int n, List<Set<A>> list) { Set<A> s1 = EnumSet.noneOf(A.class); for (A a : A.values()) { s1.add(a); } for (int i = 0; i < n; ++i) { Set<A> s2 = EnumSet.noneOf(A.class); s2.addAll(s1); list.add(s2); } } }
同様に、比較対象のHashSetに対するテスト用のクラス。
import java.util.HashSet; import java.util.List; import java.util.Set; public class HashSetTester { public void test(int n, List<Set<A>> list) { Set<A> s1 = new HashSet<A>(); for (A a : A.values()) { s1.add(a); } for (int i = 0; i < n; ++i) { Set<A> s2 = new HashSet<A>(); s2.addAll(s1); list.add(s2); } }
これらの処理の呼び出し側。
import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Set; public class Main { public static void main(String[] args) { int n = 100000; List<Set<A>> list = new ArrayList<Set<A>>(n); dumpMemoryUsage("before"); new HashSetTester().test(n, list); // new EnumSetTester().test(n, list); dumpMemoryUsage("after"); } private static void dumpMemoryUsage(String msg) { NumberFormat nf = new DecimalFormat("0.000"); Runtime rt = Runtime.getRuntime(); long max = rt.maxMemory(); long free = rt.freeMemory(); long total = rt.totalMemory(); System.out.printf("%-7s: %-7s %-7s %-7s %-7s\n", msg, "max", "total", "free", "used"); System.out.printf("%-7s: %7sMB %7sMB %7sMB %7sMB\n", "", nf.format(max / 1024.0 / 1024), nf.format(total / 1024.0 / 1024), nf.format(free / 1024.0 / 1024), nf.format((total - free) / 1024.0 / 1024)); } }
で、実行結果。
HashSetの場合。
before : max total free used : 63.562MB 1.938MB 1.273MB 0.665MB after : max total free used : 63.562MB 28.406MB 7.791MB 20.616MB
EnumSetの場合。
before : max total free used : 63.562MB 1.938MB 1.273MB 0.665MB after : max total free used : 63.562MB 7.785MB 2.628MB 5.157MB
やはり同様に差が出る。
JavaDocやソースを見てみると、こちらはビットパターンによって、列挙型のどの要素がSetに含まれているかを保持している。要素数が64個以下の場合はlong値1つだけを持つEnumSet実装(RegularEnumSet)を使用し、65個以上ある場合はlong値の配列を持つEnumSet実装(JumboEnumSet)を使用している。