简体   繁体   中英

Hotspot JVM array allocation

I've been searching for days for proper documentation on Hotspot JVM, with regards to the way arrays are allocated (an). By this, I mean what's the actual structure of the array, when allocated in memory, is it made out of contiguous blocks or is it a tree like structure.

I need the structure to come up with a formula of the size (a formula which takes size of object and array length as inputs). From the tests I've run and from what code I could understand, I've come up with arrays being contiguous structures. Like an object, they have a header, an int for counter and then the blocks for data. My tests couldn't detect structure overhead that would be incurred by using a tree like structure, though I can easily envision such an event.

If anyone here is more informed, I'd greatly appreciate it! My best results searching have yielded this link: Array memory allocation - paging Thanks!

Probably a bit late, but here it goes:

Arrays are allocated as contiguous blocks. The size can be derived by using the class sun.misc.Unsafe (Some great tutorial here ), which gives you native access to raw memory. For example, the allocated size of an array of int s is (in bytes):

Unsafe.ARRAY_INT_BASE_OFFSET + Unsafe.ARRAY_INT_INDEX_SCALE * length

Due to implementation of the hotspot-jvm, all objects are aligned to 8 or 4 bytes (depending on your platform: AMD64 or x86_32), so the actual size of an array is increased to a multiple of 8 or 4 bytes.

Using the unsafe class we can inspect the actual data:

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();
}

Which results in:

 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 

So we can see, that the integers a saved in little-endian starting at offset 16. And the integer at offset 12-16 is the length of our array. The bytes at 0-12 make up some magic number, though I am not quite sure how that works.

Note

I would advice against writing code which uses properties of your JVM, as it is highly unportable and can probably break between updates. Nevertheless, I think you can safely assume that arrays are allocated as contiguous blocks.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM