java是一门面向对象的编程语言,在编程中与对象的是紧密相连的。本篇主要讲述对象在虚拟机中的存在过程(Hotspot)。

一、对象的组成

每个对象在内存中的布局分为3部分,如图

java对象怎么存在map里面 java对象存在哪里_java对象怎么存在map里面


1.对象头

(1)markword:存储对象自身的运行时数据(哈希码,偏向线程,持有锁状态),在不同位数的虚拟机中大小不同,分别为32bit和64bit。

(2)kclass:指向对象类元数据指针,虚拟机通过这个指针来确定对象是哪个类的实例

ps(元数据:用来描述数据的数据)

(3)length:数组实例才会有,记录数组的长度

2.实例数据

对象存储的有用信息,是各种类型的字段内容,从父类继承的也会记录在实例数据中

3.对其填充

没有实际意义,只是占位符。因为虚拟机内部规定对象的大小必须是8字节的整数倍,对象头必然是8的整数倍(1倍或者2倍),那么当实例数据不是8的整数倍时,由对其填充来补全。

二、对象的创建
虚拟机遇到new指令时,先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已经被加载、解析和初始化过。若没有,则先执行相应类的加载过程。然后为新生对象分配内存,对象所需内存大小在类加载完即可完全确定。
分配内存的方式有两种
1.指针碰撞
如果java堆中的内存是绝对规整的,会有一个指针将内存分为两部分,一部分为已使用内存,一部分为空闲内存。当有新对象要分配内存时,这个指正会向空闲内存方向移动大小为新对象大小的内存区域。这种分配方式仅仅是指针的移动,称为指针碰撞。
2.空闲列表分配
如果内存不是规整的,那么虚拟机内部会维护一个列表,记录着可用的内存块。创建对象时,会从列表中找一块足够大的内存来划分给新对象(可能会造成浪费),同时更新表上的记录。
但是在多线程并发的情况下,是不安全,有以下两种解决方法

1.使用本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)

每个线程在Java堆中预先分配一小块内存,各个线程的内存分配发生在自己的TLAB区域内,只有TLAB用完需要分配新的空间时才需要同步锁定。虚拟机是否使用TLAB,可通过-XX:+/-UseTLAB参数设定。(TLAB越大,可分配的线程越少)
2.对分配内存空间的动作进行同步处理
虚拟机采用CAS(Compare and Swap,多线程操作中只有一个线程能成功,其他线程被通知竞争失败)配上失败重试的方式保证操作的原子性。

两种不同的内存分配方式取决于内存是否规整,而内存的规整与否取决于垃圾收集器是否带有压缩整理功能

内存分配完成后,虚拟机将分配到的内存空间都初始化为零值(不包括对象头),如果使用TLAB,这一工作可提前至TLAB分配时进行。虚拟机对对象进行必要的设置,如对象头、元数据等信息进行设置。最后根据init方法初始化