Java对象结构详解【MarkWord 与锁的实现原理】
Java对象存储在堆(Heap)内存。那么一个 Java对象到底包含什么呢?概括起来分为对象头、对象体和对齐字节。如下图所示:
【1】对象头中的Mark Word(标记字)主要用来表示对象的线程锁状态,另外还可以用来配合GC、存放该对象的 hashCode;
【2】Klass Word是一个指向方法区中 Class信息的指针,意味着该对象可随时知道自己是哪个 Class的实例;
【3】数组长度也是占用64位(8字节)的空间,这是可选的,只有当本对象是一个数组对象时才会有这个部分;
【4】对象体是用于保存对象属性和值的主体部分,占用内存空间取决于对象的属性数量和类型;
【5】对齐字是为了减少堆内存的碎片空间(不一定准确)。
Mark Word(标记字)

以上是 Java对象处于5种不同状态时,Mark Word中 64位的表现形式,上面每一行代表对象处于某种状态时的样子。其中各部分的含义如下:
【1】lock:2位的锁状态标记位,由于希望用尽可能少的二进制位表示尽可能多的信息,所以设置了 lock标记。该标记的值不同,整个 Mark Word表示的含义不同。biased_lock 和 lock一起,表达的锁状态含义如上图所示。
【2】biased_lock:对象是否启用偏向锁标记,只占1个二进制位。为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。lock 和 biased_lock共同表示对象处于什么锁状态
【3】age:4位的 Java对象年龄。在GC中,如果对象在 Survivor区复制一次,年龄增加1。当对象达到设定的阈值时,将会晋升到老年代。默认情况下,并行 GC的年龄阈值为15,并发GC的年龄阈值为6。由于age只有4位,所以最大值为15,这就是-XX:MaxTenuringThreshold 选项最大值为15的原因。
【4】identity_hashcode:31位的对象标识hashCode,采用延迟加载技术。调用方法 System.identityHashCode()计算,并会将结果写到该对象头中。当对象加锁后(偏向、轻量级、重量级),MarkWord的字节没有足够的空间保存hashCode,因此该值会移动到线程 Monitor中。
【5】thread:持有偏向锁的线程ID。
【6】epoch:偏向锁的时间戳。
【7】ptr_to_lock_record:轻量级锁状态下,指向栈中锁记录的指针。
【8】ptr_to_heavyweight_monitor:重量级锁状态下,指向对象监视器 Monitor的指针。
我们通常说的通过 synchronized【链接】实现的同步锁,真实名称叫做重量级锁。但是重量级锁会造成线程排队(串行执行),且会使 CPU在用户态和核心态之间频繁切换,所以代价高、效率低。为了提高效率,不会一开始就使用重量级锁,JVM在内部会根据需要,按如下步骤进行锁的升级:
【1】初期锁对象刚创建时,还没有任何线程来竞争,对象的 Mark Word是下图的第一种情形,这偏向锁标识位是0,锁状态01,说明该对象处于无锁状态(无线程竞争它)。
【2】当有一个线程来竞争锁时,先用偏向锁,表示锁对象偏爱这个线程,这个线程要执行这个锁关联的任何代码,不需要再做任何检查和切换,这种竞争不激烈的情况下,效率非常高。这时 Mark Word会记录自己偏爱的线程的ID,把该线程当做自己的熟人。如下图第二种情形。
【3】当有两个线程开始竞争这个锁对象,情况发生变化了,不再是偏向(独占)锁了,锁会升级为轻量级锁,两个线程公平竞争,哪个线程先占有锁对象并执行代码,锁对象的 Mark Word就执行哪个线程的栈帧中的锁记录。如下图第三种情形。
【4】如果竞争的这个锁对象的线程超过两个线程,导致了更多的切换和等待,JVM会把该锁对象的锁升级为重量级锁,这个就叫做同步锁,这个锁对象 Mark Word再次发生变化,会指向一个监视器对象,这个监视器对象用集合的形式,来登记和管理排队的线程。如下图第四种情形。
Klass Word(类指针)
这一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例。该指针的位长度为JVM的一个字大小,即 32位的 JVM为 32位,64位的 JVM为 64位。
如果应用的对象过多,使用 64位的指针将浪费大量内存,统计而言,64位的 JVM将会比 32位的 JVM多耗费 50%的内存。为了节约内存可以使用选项 +UseCompressedOops开启指针压缩,其中,oop即 ordinary object pointer普通对象指针。开启该选项后,下列指针将压缩至32位:
【1】每个 Class的属性指针(即静态变量);
【2】每个对象的属性指针(即对象变量);
【3】普通对象数组的每个元素指针;
当然,也不是所有的指针都会压缩,一些特殊类型的指针 JVM不会优化,比如指向 PermGen的 Class对象指针(JDK8中指向元空间的 Class对象指针)、本地变量、堆栈元素、入参、返回值和NULL指针等。
数组长度
如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,这部分数据的长度也随着 JVM架构的不同而不同:32位的JVM上,长度为32位;64位JVM则为64位。64位 JVM如果开启 +UseCompressedOops选项,该区域长度也将由64位压缩至32位。
Java对象结构详解【MarkWord 与锁的实现原理】的更多相关文章
- JAVA对象头详解(含32位虚拟机与64位虚拟机)
为什么要学习Java对象头 学习Java对象头主要是为了解synchronized底层原理,synchronized锁升级过程,Java并发编程等. JAVA对象头 由于Java面向对象的思想,在JV ...
- Java内存结构详解
Java内存结构详解 Java把内存分成:栈内存,堆内存,方法区,本地方法区和寄存器等. 下面分别介绍栈内存,堆内存,方法区各自一些特性: 1.栈内存 (1)一些基本类型的变量和对象的引用变量都是在函 ...
- Java对象初始化详解
在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Java如何执行对象的初始化做一个详细深入地介绍(与对象初始化相同,类在被加载之后也是需要初始化的,本 ...
- Java对象初始化详解(转)
在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Java如何执行对象的初始化做一个详细深入地介绍(与对象初始化相同,类在被加载之后也是需要初始化的,本 ...
- 【转】Java对象初始化详解
来源:MySun 链接:http://mysun.iteye.com/blog/1596959 在Java中,一个对象在可以被使用之前必须要被正确地初始化,这一点是Java规范规定的.本文试图对Jav ...
- 2018.6.15 Java对象序列化详解
一.定义 Serializable 序列化:把Java对象转换为字节序列的过程. 反序列化:把字节序列恢复为Java对象的过程. ObjectOutputStream对象输出流 可以将实现了Seria ...
- Java对象序列化详解
深入理解Java对象序列化 1. 什么是Java对象序列化 Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- Java 对象排序详解
很难想象有Java开发人员不曾使用过Collection框架.在Collection框架中,主要使用的类是来自List接口中的ArrayList,以及来自Set接口的HashSet.TreeSet,我 ...
- 【Java并发】详解 AbstractQueuedSynchronizer
前言 队列同步器 AbstractQueuedSynchronizer(以下简称 AQS),是用来构建锁或者其他同步组件的基础框架.它使用一个 int 成员变量来表示同步状态,通过 CAS 操作对同步 ...
随机推荐
- appium程序下载安装/appium desktop
官网地址:http://appium.io/ 点击下载按钮 默认跳转到最新版本,点击 Releases 回到版本列表页 该页可以看到对应的版本及更新时间,(最好不要下载最新版本) 如果是 Window ...
- 记录一个二级域名绑定动态ip的操作
家里的路由器,还有一台路由器需要登录,以前一直用f3322的动态域名绑定,感觉使用也还可以,但最近几个月,只要是f3322.com的二级域名全部被chrome标注为危险. 所以准备换一个免费的二级域名 ...
- shell相关基础面试题
用sed修改test.txt的23行test为tset: sed –i '23s/test/tset/g' test.txt 查看/web.log第25行第三列的内容. sed –n '25p' /w ...
- Number(数字)
Python 中的变量不需要声明.每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建. 在 Python 中,变量就是变量,它没有类型,我们所说的"类型"是变量所指的内存中对 ...
- You Don't Know JS阅读笔记
JS特性查漏补缺 [1,2,3]=="1,2,3" //true 前者会隐式转换,用逗号组合成字符串 212>'22' //true 有一个值不是number就会隐式转换成n ...
- 【PTA】1049 Counting Ones
The task is simple: given any positive integer N, you are supposed to count the total number of 1's ...
- 从xml读取gps数据获取经纬高
#!/usr/bin/python # -*- coding: UTF-8 -*- from xml.dom.minidom import parse import xml.dom.minidom & ...
- 【python】第一模块 步骤五 第二课、Python多线程
第二课.Python多线程 一.课程介绍 1.1 课程概要 章节概要 进程.线程与并发 对多核的利用 实现一个线程 线程之间的通信 线程的调度和优化 1.2 为什么要学习多线程 (线程)使用场景 快速 ...
- heimaJava18_线程
Java 线程 单线程 线程(thread)是一个程序内部的一条执行路径. main方法的执行其实就是一个单独的执行路径 程序中如果只有一条执行路径,那么这个程序就是单线程的程序 多线程 多线程是指从 ...
- 【CSS】CSS字体图标iconfont
CSS字体图标iconfont展示的是图标,本质上还是字体 使用字体图标步骤: 字体图标的下载 将字体图标引入到HTML 字体图标的追加(以后添加新的小图标) 推荐下载网站 icomoon字库http ...