有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java热点JVM阵列分配

我已经在Hotspot JVM上搜索了好几天,寻找关于数组分配方式(an)的适当文档。我的意思是,当在内存中分配时,数组的实际结构是什么,它是由连续的块组成的,还是树状结构

我需要这个结构给出一个大小的公式(一个将对象大小和数组长度作为输入的公式)。从我运行的测试和我能理解的代码来看,我发现数组是连续结构。和对象一样,它们有一个头,一个int代表计数器,然后是数据块。我的测试无法检测到使用树状结构会产生的结构开销,尽管我可以很容易地预见这样的事件

如果这里有人更了解情况,我将不胜感激!我的最佳搜索结果产生了以下链接: Array memory allocation - paging 谢谢


共 (1) 个答案

  1. # 1 楼答案

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

    数组被分配为连续块。大小可以通过使用类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字节的倍数

    使用不安全类,我们可以检查实际数据:

    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开始,整数a保存在小端。偏移量12-16处的整数是数组的长度。0-12处的字节构成了一个神奇的数字,尽管我不太确定它是如何工作的

    注意

    我建议不要编写使用JVM属性的代码,因为它非常不可移植,可能会在更新之间中断。然而,我认为您可以安全地假设数组被分配为连续块