钻牛角尖系列之JVM(二)—对象是怎么来的?

            20多年单身狗,今天我就和你们聊聊对象是怎么来的,一般没有对象我们就会new一个,那这个new到底干了什么呢?欢迎收看本期单身狗带你找对象。

            学习Java到现在,在我手下new出的对象也不少了,但是最近才想知道,1、对象是怎么来的?2、对象在内存里长啥样?3、对象在哪?(单身汪请好好看看这点)。那么下面我就一一道来:

一:对象是怎么来的?

           一言不合就new 对象,在语言层面上,创建对象通常还真就是仅仅一个new 字就搞定了(我说的对象就是普通对象不包括数组和Class对象)。我们能这么简单的创建一个对象都是JVM的功劳,虚拟机遇到一条new指令时首先会检查这个指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号代表的类是否被加载、解析、和初始化过,如果没有那必须先执行相应的类加载过程。

类加载通过后,虚拟机将要为新出生的对象分配内存(就是在内存中给它划分一个区域,这个区域来自于堆),对象所需的内存大小在类加载后就可以完全确定

虚拟机将堆中的内存分配给对象有两种方式:

           1、指针碰撞:假设堆中的内存是规整的,用过的在一片区域,没有用过的在一片区域,在两个区域中间放着一个指针。那么虚拟机再分配对象的时候就是将那个指针向空闲的一侧进行一下移动就可以了。

           2、空闲列表:这种是针对于堆中的内存不是规整的情况,这时虚拟机需要自己维护一张列表记录一下那些内存是用过的,哪些是没有用过的,在分配的时候在列表中找到一个足够的内存空间划分给对象,并更新列表上的记录。

 

           那么虚拟机到底采用哪种分配方案呢?这个主要是取决于JVM使用的垃圾收集器是否带有压缩整理功能,Serial、和ParNew这种带有压缩功能的收集器,采用的是 指针碰撞,CMS收集器使用的标记清理算法,所以它使用的空闲列表方式。

由于分配对象是很频繁的操作,那么在并发的环境下刚给对象A分配完内存,这时指针还没有来得及修改,对象B又使用原来的指针分配了内存,那么这显然是线程不安全的,解决方案有二:

           一:对分配内存的动作进行同步采用CAS加上失败重试保证原子性。

           二:把内存分配动作按照线程划分,就是内个线程在Java堆中都留有一小块内存,TLAB(Thread Local Allocation Buffer),哪个线程需要分配内存,就在谁的TLAB上分配,只有当TLAB用完需要分配新的TLAB时才会加锁同步。

内存分配完成后JVM将分配的空间都初始化为零值(除了对象头)。这一工作如果使用了TLAB也可提前至TLAB分配时进行。这就是为什么有些时候我们不赋初值也可以访问数据。然后对对象进行一些基础的设置比如(哪个类的实例,类元信息等等这些信息存放在对象头中,这就是为什么不初始化对象头的原因),那么做完了这些在JVM的角度一个对象已经产生了。

但是在Java程序的角度讲对象创建才刚刚开始(init()方法还没有执行)所有的字段都是零,执行new 指令后会接着执行<init>方法,把对象按照程序员的意愿进行初始化,这样一个真正的对象才是完全的产生出来了。

二:对象在内存里长啥样?

对象在内存中存储的布局可以分为三个区域:对象头、实例数据、对其填充。

           1、对象头:分为两部分a、存储对象自身的运行时数据:哈希码、锁状态、GC分代年龄等等;b、类型指针。

           2、实例数据:是对象存储的真正有效信息。

           3、对其填充:起着占位符的作用因为HotSpotVM需要对象起始地址必须是8字节的整数倍。

三:对象在哪?

Java程序是通过栈上的reference数据来操作 堆上的具体对象。reference引用只是一个指向对象的引用,主流的访问方式有下面两种:

           1、句柄池:在Java堆中划分出一块内存作为句柄池,reference存储的是对象的句柄地址。如下图:

           

           2、直接指针访问:reference存储的直接就是对象地址。如下图:

           

各自优势:使用句柄的好处就是存储的是稳定的句柄地址,在对象移动的时候不需要修改reference。直接指针的方式就是访问的更加快速,节省了一次指针定位的时间。

完活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值