FYI, here is the admittedly very clumsy and overkill-y, but effective, code that I used to make the measurements. Run it with -Xms2g or you'll get garbage results. Then I painstakingly studied the output by hand to come up with the simple formulas.
import com.google.common.collect.*;
import java.util.*;
import java.util.concurrent.CountDownLatch;
public class MapMemory {
private static final Runtime rt = Runtime.getRuntime();
public static void main(String[] args) throws Exception {
Map<Integer, String>[] holders = new Map[10];
Integer[] integers = new Integer[200000];
for (int i = 0; i < 200000; i++) {
integers[i] = new Integer(i);
}
List<Integer> list = Arrays.asList(integers);
Collections.shuffle(list);
for (int count = 0 ; count < 3; count++) {
for (int size : Arrays.asList(160000, 140000, 120000, 100000, 80000, 60000, 50000, 40000, 30000, 25000, 20000, 18000, 16000, 14000, 12000, 10000, 9000, 8000, 7000, 6000)) {
for (int i = 0; i < 10; i++) {
holders[i] = Maps.newHashMapWithExpectedSize(size);
for (Integer intagar : list.subList(0, size)) {
holders[i].put(intagar, "");
}
}
// ... then try it this way instead ...
// ImmutableMap.Builder<Integer, String> builder = ImmutableMap.builder();
// for (Integer intagar : list.subList(0, size)) {
// builder.put(intagar, "");
// }
// for (int i = 0; i < 10; i++) {
// holders[i] = builder.build();
// }
// builder = null;
gcTillYouDrop();
long mem = rt.freeMemory();
for (int i = 0; i < 10; i++) {
holders[i] = null;
}
gcTillYouDrop();
long diff = rt.freeMemory() - mem;
System.out.format("%s - %s%n", size, diff / 10);
}
System.out.println();
}
}
// Standard hyper-paranoid "gc everything" procedure from Martin Buchholz
static void gcTillYouDrop() {
rt.gc();
rt.runFinalization();
final CountDownLatch latch = new CountDownLatch(1);
new Object() {
protected void finalize() {
latch.countDown();
}
};
rt.gc();
try {
latch.await();
}
catch(InterruptedException ie){
throw new Error(ie);