可能有点晚了,但它是这样的:
数组被分配为连续的块。大小可以通过使用sun.misc.Unsafe类(这里有一些很棒的教程)来派生,它使您可以本机访问原始内存。例如,int
s 数组的分配大小为(以字节为单位):
Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * length
由于hotspot-jvm 的实现,所有对象都对齐到8 或4 字节(取决于您的平台:AMD64 或x86_32),因此数组的实际大小增加到8 或4 字节的倍数。
使用 unsafe 类,我们可以检查实际数据:
public static void main(String[] args) {
//Get the unsafe object.
Unsafe unsafe = null;
try {
Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (sun.misc.Unsafe) field.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
//define our array
int[] data = new int[]{0,1,2,3,4,5,6,7,8,9};
//calculate length (ignoring alignment)
int len = Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * data.length;
//Some output formatting
System.out.print(" 0| ");
for(int i = 0; i < len; i++){
//unsafe.getByte retrieves the byte in the data struct with offset i
//This is casted to a signed integer, so we mask it to get the actual value
String hex = Integer.toHexString(unsafe.getByte(data, i)&0xFF);
//force a length of 2
hex = "00".substring(hex.length()) + hex;
//Output formatting
System.out.print(hex);
System.out.print(" ");
if(i%4 == 3 && i != len -1){
System.out.println();
if(i < 9){
System.out.print(" ");
}
System.out.print((i+1) +"| ");
}
}
System.out.println();
}
结果是:
0| 01 00 00 00
4| 00 00 00 00
8| 32 02 8c f5
12| 08 00 00 00
16| 00 00 00 00
20| 01 00 00 00
24| 02 00 00 00
28| 03 00 00 00
32| 04 00 00 00
36| 05 00 00 00
40| 06 00 00 00
44| 07 00 00 00
所以我们可以看到,整数 a 保存在 little-endian 中,从偏移量 16 开始。偏移量 12-16 处的整数是我们数组的长度。0-12 的字节组成了一些幻数,尽管我不太确定它是如何工作的。
笔记
我建议不要编写使用 JVM 属性的代码,因为它是高度不可移植的,并且可能会在更新之间中断。不过,我认为您可以放心地假设数组是作为连续块分配的。