In-depth understanding of memory layout objects of the Java Virtual Machine

Reproduced, please indicate the original source, thank you!

HappyFeet's blog


In HotSpot virtual machine, objects in memory layout is divided into three storage areas: object header (Header), instance data (InstanceData) and alignment padding (Padding).

First, the memory layout of objects

1, object header (Header)

Object head HotSpot virtual machine includes the following information:

"Mark Word":

Storage object itself runtime data, such as: the hash code (HashCode), GC generational age, the lock status flags, thread holds the lock, missed the thread ID, timestamp bias. This part of the length of data in 32-bit and 64-bit virtual machines are 32 bit and 64 bit. Figure:

HotSpot virtual machine object head Mark Word

But just look at this is very easy to look ignorant force, fortunately HotSpot virtual machine markOop.cpp in good comments, to 64, for example:

// The markOop describes the header of an object.
//  ...
//  64 bits:
//  --------
//  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
//  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
//  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
//  size:64 ----------------------------------------------------->| (CMS free block)
//
//  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
//  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
//  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
//  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
//	...
//
//    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
//    [0           | epoch | age | 1 | 01]       lock is anonymously biased
//
//  - the two lock bits are used to describe three states: locked/unlocked and monitor.
//
//    [ptr             | 00]  locked             ptr points to real header on stack
//    [header      | 0 | 01]  unlocked           regular object header
//    [ptr             | 10]  monitor            inflated lock (header is wapped out)
//    [ptr             | 11]  marked             used by markSweep to mark an object
//                                               not valid at any other time
//
//    We assume that stack/thread pointers have the lowest two bits cleared.
复制代码

Click to view full comment

The table read together with comments, obviously much easier to understand and more, spend some time painting a color chart below helps to understand:

HotSpot virtual machine object head Mark Word

Mark Word in a different state, which is different data structures, such non-fixed data structures for storage in a very small space as much information.

For example: When the lock is 01, biased_lock is 1, Mark Word is in a biased state. At this time, before the 54 bit bias thread ID is stored, followed by 2 bit time stamp is biased, 1 bit is not used, 4 bit object generational Age;

When Mark Word is in a biased state, the thread ID is 0 for deflecting the anonymous biased locking.

"Klass":

Type pointer to the class object's metadata (area method) of the pointer, the virtual machine is determined by the pointer of this object belongs to which class. This part of the length of data in 32-bit and 64-bit virtual machines are 32 bit and 64 'bit (if compression was turned pointer 4 bytes).

"Array Length": If the object is a Java array, then the object as well as a head for recording the data length of the array

For determining the size of the array, int type, a size of 4 bytes.

2, instance data (InstanceData)

Data type length
reference: In the 32-bit and 64-bit virtual machines are always 4 bytes and 8 bytes (if compression was turned pointer 4 bytes).

3, alignment padding (the Padding)

Not necessarily exist, no special meaning, just a placeholder for the role. Because HotSpot VM automatic memory management system requires the starting address of the object must be an integer multiple of 8 bytes, when the object size is not aligned by the alignment needs to be filled completion.

Therefore, the object memory layout diagram is as follows:

Memory object layout

Second, let's look at an example:

/**
 * environment:
 *     java version "1.8.0_101"
 *     Java(TM) SE Runtime Environment (build 1.8.0_101-b13)
 *     Java HotSpot(TM) 64-Bit Server VM (build 25.101-b13, mixed mode)
 * VM options: 
 * 		-XX:+UseCompressedOops 使用指针压缩;
 * 	 	-XX:-UseCompressedOops 不使用指针压缩;
 */
public class MemoryUseTest {

    private static Unsafe unsafe;
    
	// 为了获取 field 的 offset
    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);
            unsafe = (Unsafe) f.get(null);
        } catch (Exception e) {
        }
    }

    public static Unsafe getUnsafe() {
        return unsafe;
    }

    public static void main(String[] args) {

        MemoryUse obj = new MemoryUse();
        System.out.println("obj shallow size is : " + MemoryUtil.memoryUsageOf(obj));
        System.out.println("obj deep size is : " + MemoryUtil.deepMemoryUsageOf(obj) + "\n");

        System.out.println("obj offset is : ");
        for (Field field : obj.getClass().getDeclaredFields()) {
            System.out.println("\t offset : " + getUnsafe().objectFieldOffset(field) + ", field name : " + field.getName());
        }

    }

    static class MemoryUse {
        long long0;
        int int0;
        long long1;
        byte byte0;
        short short0;
        String str0 = "hello world";
    }
}
复制代码

1, open pointer compression, the output results are as follows:

-XX:+UseCompressedOops
output:
	obj shallow size is : 40
	obj deep size is : 104
	
	obj offset is : 
		 offset : 16, field name : long0
		 offset : 12, field name : int0
		 offset : 24, field name : long1
		 offset : 34, field name : byte0
		 offset : 32, field name : short0
		 offset : 36, field name : str0
复制代码

We according to fieldthe offsetlength of the data with examples to analyze objthe sizewhy is this result:

(1) obj: 40 (ie shallow size: when encountered references, only references to the calculated length, does not calculate the actual magnitude of the object referenced)

Open obj pointer compression

Mark Word(8) + Klass(4) + int0(4) + long0(8) + long1(8) + short0(2) + byte0(1) + Padding(1) + str0(4) = 40

(2)str0 : 24

Open pointer compression str0

Mark Word(8) + Klass(4) + hash(4) + value[](4) + Padding(4) = 24

(3)value[] : 40

Compression Open pointer value []

Mark Word(8) + Klass(4) + Array Length(4) + Instance Data(11*2) + Padding(2) = 40

The final objtake up memory size40 + 24 + 40 = 104 bytes

(Ie deep size: i.e. encountered references, the actual size will also referenced object calculated, as in the example str0);

From the point of view of the illustrated example, the order of fields and stores its stated order in a subject not identical. This is because:

HotSpot 虚拟机默认的分配策略为 longs/doubles、ints、shorts/chars、bytes/booleans、oops(Ordinary Object Pointers),从分配策略中可以看出,相同宽度的字段总是被分配在一起。
复制代码

2, pointer compression does not open, the output results are as follows:

-XX:-UseCompressedOops
output:
	obj shallow size is : 48
	obj deep size is : 128
	
	obj offset is : 
		 offset : 16, field name : long0
		 offset : 32, field name : int0
		 offset : 24, field name : long1
		 offset : 38, field name : byte0
		 offset : 36, field name : short0
		 offset : 40, field name : str0
复制代码

Similarly available:

(1) obj: 48 (ie shallow size: when encountered references, only references to the calculated length, does not calculate the actual magnitude of the object referenced)

Do not turn on compression pointer obj

Mark Word(8) + Klass(8) + long0(8) + long1(8) + int0(4) + short0(2) + byte0(1) + Padding(1) + str0(8) = 48

(2)str0 : 32

Pointer does not turn on compression str0

Mark Word(8) + Klass(8) + value[](8) + hash(4) + Padding(4) = 32

(3)value[] : 48

Compression is not turned pointer value []

Mark Word(8) + Klass(8) + Array Length(4) + Instance Data(11*2) + Padding(6) = 48

The final objtake up memory size48 + 32 + 48 = 128 bytes

Third, what is the significance of understanding the object memory layout?

Grasp the object layout in memory lets us know that the virtual machine memory in the end is how it is used, and how to adjust the code to reduce memory overhead.

References:

(1) "in-depth understanding of java virtual machine," the second edition of the Zhou Zhiming.

(2)Primitive Data Types

(3)Category Archives: Java Object Memory Structure

Guess you like

Origin juejin.im/post/5e3ec6e9f265da57537ea51f