java对象的内存布局

对象在内存中划分的区域

对象头中标识字段存储的数据

HotSpot虚拟机中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。

1)对象头:包括标记字段和类型指针两部分内容(注:如果是数组对象,则包含三部分内容):

	1)Mark Word(标记字段):用于存储运行时对象自身的数据。
		1>占用内存大小与虚拟机位长(64位的HotSpot虚拟机下为8个字节)一致,在运行期间,考虑到JVM的空间效率,Mark Word被设计成为一个非固定的数据结构,以便存储更多有效的数据。
		2>存储运行时对象自身的数据:
		
			哈希码(hash)
			GC分代年龄(age)
			锁标识位:
				01	无锁
				01	偏向锁
				00	轻量级锁
				10	重量级锁
			偏向锁标识位(biased_lock)
				0	无锁
				1	偏向锁
			偏向线程ID(JavaThread*)
			偏向时间戳(epoch)
			
			说明:锁标识位、偏向锁标识位、偏向线程ID等的具体实现均是在monitor对象中完成的。(源码中的ObjectMonitor对象)
		
		3>Mark Word里存储的数据会随着锁标志位的变化而变化,即不同的锁状态,存储着不同的数据:
		
			锁状态		存储内容							锁标识位		偏向锁标识位(是否是偏向锁)		
			--------	------------------------------		--------		--------
			无锁状态	哈希码、GC分代年龄					01				0
			偏向锁		线程ID、偏向时间戳、GC分代年龄		01				1
			轻量级锁	指向栈中锁记录的指针  				00				无
			重量级锁	指向monitor的指针					10				无
			GC标记		无								11				无
	
	2)Class Metadata Address(类型指针):指向对象的类元数据(方法区的Class数据),虚拟机通过这个指针确定该对象是哪个类的实例,若开启指针压缩,则类型指针占用4个字节。
	
	3)如果对象是数组类型,则对象头中还存储着数组的长度,占用4个字节。
	
	
		
2)实例数据:存放类的属性数据信息,包括父类的属性信息。


3)对齐填充:由于虚拟机要求对象起始地址必须是8字节的整数倍,即每个对象所占内存的字节数必须是8的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐。
	

4)使用JOL(Java Object Layout)工具查看java对象的内存布局:

	maven依赖:
		<dependency>
		    <groupId>org.openjdk.jol</groupId>
		    <artifactId>jol-core</artifactId>
		    <version>0.14</version>
		</dependency>

	代码:
		public class TestClassLayout {

		    public static void main(String[] args) {

		        TestClass[] testClassObj = new TestClass[5];

		        // 查看对象内存布局
		        System.out.println(ClassLayout.parseInstance(testClassObj).toPrintable());
		    }
		}	


	结果:
		1	[Lcom.jxn.test.TestClass; object internals:
		2	 OFFSET  SIZE                     TYPE DESCRIPTION                               VALUE
		3	      0     4                          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
		4	      4     4                          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
		5	      8     4                          (object header)                           82 c1 00 f8 (10000010 11000001 00000000 11111000) (-134168190)
		6	     12     4                          (object header)                           05 00 00 00 (00000101 00000000 00000000 00000000) (5)
		7	     16    20   com.jxn.test.TestClass TestClass;.<elements>                     N/A
		8	     36     4                          (loss due to the next object alignment)
		9	Instance size: 40 bytes
		10	Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

		对象头:
			第3行+第4行:	Mark Word(标记字段)
			第5行:		类型指针
			第6行:		数组长度
		实例数据:
			第7行:		数组中存储了5个TestClass对象的引用(开启指针压缩后,类型引用占4个字节),故占用5*4=20个字节。
		对齐填充:
			第8行:		对象头+实例数据 占用的内存为36字节(不是8的整数倍),故需要4字节的对齐填充。

		对象占用的总空间:
			第9行

		内存浪费的总空间:
			第10行:		对齐填充消耗了4个字节。

			说明:若数组的长度改为6,则 对象头+实例数据 占用的内存为40字节(8的整数倍),故不会出现对齐填充:

			[Lcom.jxn.test.TestClass; object internals:
			 OFFSET  SIZE                     TYPE DESCRIPTION                               VALUE
			      0     4                          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
			      4     4                          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
			      8     4                          (object header)                           82 c1 00 f8 (10000010 11000001 00000000 11111000) (-134168190)
			     12     4                          (object header)                           06 00 00 00 (00000110 00000000 00000000 00000000) (6)
			     16    24   com.jxn.test.TestClass TestClass;.<elements>                     N/A
			Instance size: 40 bytes
			Space losses: 0 bytes internal + 0 bytes external = 0 bytes total




	
5)hotspot/src/share/vm/oops/markOop.hpp 源码中的说明:

	// The markOop describes the header of an object.
	//
	// Note that the mark is not a real oop but just a word.
	// It is placed in the oop hierarchy for historical reasons.
	//
	// Bit-format of an object header (most significant first, big endian layout below):
	//
	//  32 bits:
	//  --------
	//             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
	//             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
	//             size:32 ------------------------------------------>| (CMS free block)
	//             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted 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)
	//
	//  - hash contains the identity hash value: largest value is
	//    31 bits, see os::random().  Also, 64-bit vm's require
	//    a hash value no bigger than 32 bits because they will not
	//    properly generate a mask larger than that: see library_call.cpp
	//    and c1_CodePatterns_sparc.cpp.
	//
	//  - the biased lock pattern is used to bias a lock toward a given
	//    thread. When this pattern is set in the low three bits, the lock
	//    is either biased toward a given thread or "anonymously" biased,
	//    indicating that it is possible for it to be biased. When the
	//    lock is biased toward a given thread, locking and unlocking can
	//    be performed by that thread without using atomic operations.
	//    When a lock's bias is revoked, it reverts back to the normal
	//    locking scheme described below.
	//
	//    Note that we are overloading the meaning of the "unlocked" state
	//    of the header. Because we steal a bit from the age we can
	//    guarantee that the bias pattern will never be seen for a truly
	//    unlocked object.
	//
	//    Note also that the biased state contains the age bits normally
	//    contained in the object header. Large increases in scavenge
	//    times were seen when these bits were absent and an arbitrary age
	//    assigned to all biased objects, because they tended to consume a
	//    significant fraction of the eden semispaces and were not
	//    promoted promptly, causing an increase in the amount of copying
	//    performed. The runtime system aligns all JavaThread* pointers to
	//    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
	//    to make room for the age bits & the epoch bits (used in support of
	//    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
	//
	//    [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.

	

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值