对象的创建

文章内容是学习过程中的知识总结,如有纰漏,欢迎指正

文章目录

前言

1. 对象创建

1.1. 概述

1.2. 内存分配

2. 内存布局

 2.1. 对象头

2.2. 实例数据

2.3. 对齐填充

3. 对象的访问

3.1. 句柄访问

3.2. 直接地址

总结


前言

其他文章我们介绍了从class字节码文件加载到jvm内存的过程。

接下来,我们看jvm里的代码跑起来以后,在运行过程中,对象的创建和销毁在内存中经历了什么样的事情。


以下是本篇文章正文内容

1. 对象创建

1.1. 概述

从你new一个对象开始,发生了什么?

遇到new指令,jvm首先要做的事是检查有没有这个类,没有的话,加载它!

1.2. 内存分配

类加载检查通过后,就要给新对象分配内存。

因为一个类型确定后,它内部定义了哪些结构哪些值,所需要的内存空间也就确定了。先给他划出来。

(具体对象的内存布局,在下一小节)

但是这个内存分配,具体怎么划出来,有不同的方式:

1)指针碰撞(Bump The Pointer)

这种分配前提是内存中有整片连续的空间,用的在一边,空闲的在另一边,一个指针指向分界线。

需要多少指针往空闲那边移动多少,直接划分出来一段,给当前对象,完工。

2)空闲列表(Free List)

那如果jvm堆不那么规整呢?用的和没用的交叉在一起,也就是我们所说的内存碎片。

这种情况就需要我们单独有一张表来记录,哪些内存块是空的。

分配的时候查表,找到大小够用的一块,分配给对象,同时更新列表。

具体哪种方式,和我们的垃圾回收器有关系。有的垃圾回收器会对内存做整理压缩,那就指针碰撞简单高效。如果没有压缩功能,那只能是采用空闲列表

3)并发性

无论指针移动还是空闲列表的同一个指针空间,在并发分配的情况下会不会有问题?

确实有并发问题。那jvm是如何解决的呢?

方式一:cas原子操作 + 失败重试

方式二:本地线程分配缓冲(TLAB)

全称是 Thread Local Allocation Buffer

-XX:+/-UseTLAB 默认开启

-XX:TLABSize=size配置空间大小,默认512k。

我们知道,对于栈、计数器,每个线程独享,堆是共享的。

但实际上,我们可以让线程在创建时,先独享划走一部分堆。

那么线程创建对象需要内存时,可以在自己划走的堆上先操作。相当于每个线程批发了一批内存先用着。

当前线程空间不够时,再去公共堆上申请,这样就减少了并发冲突的机会。当然也多少有点浪费

2. 内存布局

上面我们给这个对象分配好了内存空间,那么问题来了。对象拿走的这块内存,它都写了些啥进去呢?

对象在堆上的布局,可以分为三个部分:对象头、实例数据、对齐填充。

 

 2.1. 对象头

对象头一般分为两部分,Mark Word 和 类型指针(Hotspot)

1)Mark Word,官方叫法,其实就是存储对象自己运行时的数据

如哈希码、GC分代年龄、锁状态标记、线程持有的锁、偏向的线程id……(不用记)

2)类型指针

指向当前对象的类型。也就是方法区里,类信息的地址。

当然这里不是绝对的,hotspot这么设计。在5.3对象访问一节,还会看到其他方式。

2.2. 实例数据

对象里各个字段的值。这个好理解。

long,double,int等长度都是固定的

string、对象类型等是个地址,指向其他外部堆空间

2.3. 对齐填充

不是必须的。就是个占位符而已。

Hotspot规定的,内存管理系统要求对象的大小必须是8字节的整数倍。

这个在对象头上,已经被精心设计过,满足要求。

但是!实例数据部分不一定。如果没有对齐的话,通过这里的对齐填充补满它。没有别的意义。

3. 对象的访问

对象创建了,就要用,它在堆里。

我们的程序运行时,大家知道,每一个方法相关的变量信息都在栈里。那么怎么找到这个对象呢?

一般来讲,两种方案:

3.1. 句柄访问

句柄方式:

栈指针指向堆里的一个句柄的地址,这个句柄再定义俩指针分别指向类型和实例

很显然,垃圾回收移动对象的话只需要改句柄即可,不会波及到栈,但是多了一次寻址操作

3.2. 直接地址

直接地址:

栈指针指向的就是实例本身的地址,在实例里封装一个指针指向它自己的类型

很显然,垃圾回收移动对象要改栈里的地址值,但是它减少了一次寻址操作。

备注:hostspot使用的是直接地址方式


总结

这里对文章进行总结:
内存布局:

  • 对象头
  • 实例数据
  • 对齐填充

对象访问方式:

  • 句柄访问
  • 直接地址
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值