阿里大牛带你了解 Java物件底层原理 号作者码到成功 作为一个java程序员,我们每天都在建立各种物件,但是你有没有思考过,当你new一个物件的时候,jvm做了哪些工作呢?今天就让我们一起来研究下,java物件的底层原理。 物件的分配 一个物件的建立可以分为以下几步。 检查载入、分配内存、内存空间初始化、设定、物件初始化 下面我们一一来分析每一个步骤 1)检查载入 jvm首先会去载入我们的class件,这个步骤可以从本地载入,也可以从网络中去载入 2)分配内存 我们首先提出两个问题 jvm是如何确可用的内存空间的 如果有两个执行绪同时new物件,如何避免分配的内存空间重叠(并发安全问题)
下面我们一一解释这两个问题
jvm是如何确可用的内存空间的
指标碰撞
如果堆内存区域规整,所有用过的内存放在一边,没用过的放在一边,中间有一个指标来指示,那分配内存就是把那个指标向空闲的区域移动一段距离(物件的大小),如下图所示
空闲列表
如果内存区域不规整,已使用和未使用的区域相互交错,采用空闲列表的方式,虚拟机器会维护一个列表,列表上记录了哪些区域使用了,哪些区域未使用.,分配的时候就从列表中找一块足够大的空间给物件,堆中的内存区域是否规整,取决于采用的垃圾收集器是否带有压缩功能。
发安全问题
如何解决并发安全呢,jvm采用了两种方式cas和tlab
CAS机制
分配内存的时候采用cas机制,保证分配的原子性
分配缓冲(TLAB)
每个执行绪在java堆中,预先分配一块私有的内存地址,执行绪如果需要分配内存,就在自己的这个私有的这个区域分配
当空间不足的时候,再从eden区申请一块继续使用
3)内存空间初始化
内存分配完毕后,将分配到内存空间都初始化0值。比如int就初始化成0,boolean就设定成false。
注意这里的初始化是jvm的初始化。
这一步保证了java的物件例项字段,在java程式码中可以不赋值,就可以直接使用。
4)设定
虚拟机器对物件的头部进行一些必要的设定
如这个物件是哪个类的示例
如何才能找到类的元资料资讯
物件的gc分代年龄等资讯
这些都存放在物件的头部中
5)物件初始化
上面的步骤完成以后,对于jvm虚拟机器来说,一个新的物件已经产生了,但是从java程式的角度来说物件的建立才刚刚开始。
这一步就是给物件赋值,并执行构造方法
物件的访问定位
经过上面的分析,我们已经掌握了如何去建立一个物件了。
那么接下去我们要分析的就是,如何去jvm里访问到我们建立的物件
控制代码池
jvm中回去维护一个控制代码池,控制代码池中的物件,存放两个资讯,一个是物件例项的地址,一个是物件所对应类的地址
然后,我们的引用直接指向控制代码池中的的元素。
这样设计的好处是,物件在jvm中由于gc,所以地址的变化是十分频繁的,用控制代码池就可以将我们对物件的引用,和物件的实际位置隔离开来,物件位置发生变化的时候,reference不用更改,减少了维护的开销
直接指标
直接指标去掉了控制代码池,直接将reference指向了我们的物件例项,然后物件的头部又存放着物件的型别。
这样的模式的优点,相对于使用控制代码池就减少了一次地址的定位的开销,由于物件的访问很频繁,积少成多,可是很可观的
欢迎关注我们,一群热爱程式设计的码农,爱生活,更爱程式设计!