阿里大牛带你了解 Java物件底层原理

阿里大牛带你了解 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指向了我们的物件例项,然后物件的头部又存放着物件的型别。

这样的模式的优点,相对于使用控制代码池就减少了一次地址的定位的开销,由于物件的访问很频繁,积少成多,可是很可观的

欢迎关注我们,一群热爱程式设计的码农,爱生活,更爱程式设计!