When creating the backing array for (e.g.) a collection, you do not really care about the exact size of the array you create, it only needs to be at least as large as you ca
Interesting idea. I think that the more portable method of determining this would be to actually measure usage. Example program:
public class FindMemoryUsage {
public static void main(String[] args) {
for (int i=0; i<50; i+=2) {
long actual = getActualUsageForN(i);
System.out.println(i + " = " + actual);
long theoretical = getTheoreticalUsageForN(i);
if (theoretical != actual) {
throw new RuntimeException("Uh oh! Mismatch!");
}
}
}
private static long getTheoreticalUsageForN(long count) {
long optimal = (Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * count);
return ((optimal - 1) & ~7) + 8;
}
private static long getActualUsageForN(int count) {
System.gc();
byte[][] arrays = new byte[3000000][];
long begin = usedMemory();
for (int i=0; i
This program gives you this info:
0 = 16
2 = 16
4 = 16
6 = 24
8 = 24
10 = 24
12 = 24
14 = 32
16 = 32
18 = 32
20 = 32
22 = 40
24 = 40
26 = 40
28 = 40
30 = 48
32 = 48
34 = 48
36 = 48
38 = 56
40 = 56
42 = 56
44 = 56
46 = 64
48 = 64
This data is from both the actual calculation of usage and the theoretical usage based on sun.misc.Unsafe's constants and 8-byte-rounding. This means that you could use these constants to "round up" like you suggested:
private static int roundSizeUp(int from) {
long size = (Unsafe.ARRAY_BYTE_BASE_OFFSET + Unsafe.ARRAY_BYTE_INDEX_SCALE * from);
long actual = ((size - 1) & ~7) + 8;
return (int) (actual - Unsafe.ARRAY_BYTE_BASE_OFFSET) / Unsafe.ARRAY_BYTE_INDEX_SCALE;
}
This is VM-specific code, but you could probably find how to do this based on the getActualUsageForN strategy if you need more portability.
Note that this isn't production-quality code: you'd want to think carefully about overflows and change the Unsafe references to be the constants that actually apply to the type of array that you're working with.