java面试题网站:www.javaoffers.com
java对象的结构这里简单的说一下:对象头,对象实际数据,对齐填充。
对象头:包含两部分 1:MarkWord (自身运行数据) , 2:类型指针
# markWord: hash码,对象所属的年代,线程持有的锁对象,锁状态标志,偏向线程ID,偏向时间等
状态的不同,markword存储的内容也是不同的。(那么读者很有可能会思考一个问题,那原来的数据比如hash码,分代年龄都不要了吗,答案是复制到其他地方去了)
#类型指针: 用于存储指向方法区对象类型数据的指针,如果是数组对象的话,还会有一个额外的部分用于存储数组长度。
对象实际数据:即我们创建对象时,对象中成员变量,方法,等。
对齐填充(不一定存在):并没有实际的意义,因为java对象默认占用内存为8字节的整倍数,如果一个对象的大小不够8字节的整倍数,那么对齐填充的作用就是填充字节,使他成为8字节的整倍数,(当java内存对象刚好是8字节的整倍数时,就不需要对齐填充了,)
偏向锁的作用:在单线程(非并发情况,即没有竞争锁的时候)访问同步代码块的时候,可以忽略同步锁机制,来提升性能,
举例:
比如有一线程A,第一次访问同步代码块,申请锁对象,拿到锁对象后,把线程A的ID 写入对象头即偏向线程ID,会把锁对象的标志位改为01,即偏向锁状态,此时线程A再次进入同步代码块的时候,则直接忽略掉同步代码块,这样就达到提高性能的作用。(在并发时,偏向锁是多余的们也可以理解为不存在的,因为他会自动升级为轻量级锁,和重量级锁,)
偏向锁原理:
偏向锁是JDK 1.6中引入的一项锁优化,假设当前虚拟机启用了偏向锁(启用参数-XX:+UseBiasedLocking,这是JDK 1.6的默认值),那么,当锁对象第一次被线程获取的时候,虚拟机将会把对象头中的标志位设为“01” (默认标志位就是01),即偏向模式。同时使用CAS操作把获取到这个锁的线程的ID记录在对象的Mark Word之中,如果CAS操作成功,持有偏向锁的线程以后每次进入这个锁
相关的同步块时,虚拟机都可以不再进行任何同步操作。
这里再提示一下与轻量级锁的区别:
轻量级在没有竞争的情况下会利用 CAS(注:Compare And Swap )来管理 互斥量(注:解锁和加锁这两种状态),来实现同步,而偏向锁则直接忽略同步块。
二者都属于乐观所。即同步时期都认为没有其他线程进行锁的争取。
最后附上java对象的内存结构图(网上找的感觉挺形象的,方便大家理解内存结构):