2

关于分配数组的方式(an),我一直在寻找有关 Hotspot JVM 的正确文档。通过这个,我的意思是数组的实际结构是什么,当在内存中分配时,它是由连续块组成还是树状结构。

我需要这个结构来提出一个大小公式(一个以​​对象大小和数组长度为输入的公式)。根据我运行的测试和我能理解的代码,我想出了数组是连续的结构。像一个对象一样,它们有一个标题,一个用于计数器的 int,然后是用于数据的块。我的测试无法检测到使用树状结构会产生的结构开销,尽管我可以轻松设想这样的事件。

如果这里有人更了解情况,我将不胜感激!我搜索的最佳结果产生了这个链接: 数组内存分配 - 分页 谢谢!

4

1 回答 1

5

可能有点晚了,但它是这样的:

数组被分配为连续的块。大小可以通过使用sun.misc.Unsafe类(这里有一些很棒的教程)来派生,它使您可以本机访问原始内存。例如,ints 数组的分配大小为(以字节为单位):

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 属性的代码,因为它是高度不可移植的,并且可能会在更新之间中断。不过,我认为您可以放心地假设数组是作为连续块分配的。

于 2012-12-28T14:35:25.077 回答