几天来,我一直在寻找关于Hotspot JVM的适当文档,关于数组的分配方式(an)。我的意思是,当分配到内存中时,数组的实际结构是什么,它是由连续的块组成的,还是树状结构。
我需要结构提出一个大小的公式(一个以对象的大小和数组长度作为输入的公式)。从我运行的测试和我能理解的代码中,我得出了数组是连续结构的结论。就像一个对象一样,它们有一个头,一个int代表计数器,然后是数据块。我的测试无法检测到使用树状结构会产生的结构开销,尽管我可以很容易地想象到这样的事件。
如果在座的任何人消息灵通,我将不胜感激!我的最佳搜索结果是这个链接:Array memory allocation - paging,谢谢!
发布于 2012-12-28 22:35:25
可能有点晚了,但它是这样的:
数组被分配为连续的块。这个大小可以通过使用类sun.misc.Unsafe (一些很棒的教程here)来派生,这个类允许您本机访问原始内存。例如,int数组的分配大小为(以字节为单位):
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 所以我们可以看到,从偏移量16开始,整数以小端的形式保存。偏移量12-16的整数是数组的长度。0-12的字节组成了一个神奇的数字,尽管我不太确定它是如何工作的。
便笺
我建议不要编写使用JVM属性的代码,因为它是高度不可移植的,并且可能在两次更新之间中断。然而,我认为您可以安全地假设数组是作为连续块分配的。
https://stackoverflow.com/questions/12714064
复制相似问题