前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Jvm对象创建-JVM(六)

Jvm对象创建-JVM(六)

作者头像
用户9919783
发布2023-09-05 14:32:24
1390
发布2023-09-05 14:32:24
举报
文章被收录于专栏:后端从入门到精通

上篇文章说了jvisualvm工具查看年轻代老年代gc过程。

Jvisualvm&内存模型剖析-JVM(五)

一、jvm创建对象

之前我们介绍了类的加载,这篇文章要介绍类的创建,过程主要是:

1、类的加载检查-----(是否已加载)

2、否的话,则加载类,是的话直接进入第三步

3、直接分配内存空间。

4、初始化

5、设置对象头

6、执行方法

1、类加载检查

虚拟机遇到new指令,首先检测这个类是否在常量池中定位到类的符号引用,检测这个符号是否被加载、解析和初始化过,没有的话则必须先加载类。

2. 分配内存

接下来虚拟机为新生对象分配内存,为对象分配内存等同于把一定大小的内存从java堆中划分出来。

但这会有两个问题:

1)如何划分内存。

2)并发情况下,在给对象A划分内存时候,指针还没来得及修改,在同一位置又给B划分内存。

划分内存分为两种,指针碰撞和空闲列表。

指针碰撞(Bump the Pointer):默认是指针碰撞,如果java内存是绝对规整的,所有用过内存都放在一边,空闲的放在另一边,中间放指针分解指示器,当分配内存后,就把指针移动到右侧。

空闲列表(Free List):如果java堆内存并不是规整的,已使用和空闲的内存相互交错,那么就没办法简单的指针碰撞,虚拟机会维护一个空闲列表,看哪些可用。

第一个划分问题策略已给出,那么如何解决并发问题呢。

有两种方式可以解决,CAS和本地线程分配缓冲TLAB。

CAS(compare and swap):比较和交换用cas配合失败重试机制来解决并发问题。

TLAB(thread local allocation buffer):把内存划分的动作按照线程划分在不同的空间,即每个线程在java堆中预分配一小块内存。通过-XX:+/UseTLAB参数设置虚拟机是否使用TLAB,而它的大小设置用的是-XX:TLABSize。

3、初始化

初始化就是前面说过的,当initDate在创建阶段,并不是直接把666赋值,而是先赋值0,String会先赋值null等。

4、设置对象头

前面初始化为0之后,虚拟机要对对象进行必要设置,例如哪个对象是哪个类实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息,这些信息都存在对象的对象头Object Header中。

在hotSpot虚拟机中,对象内存中布局分为三块区域:对象头(header)、实例数据(instance data)、和对齐填充(Padding)。

1)对象头(Object header)

Mark word:

有Mark word标记字段(32位占4字节,64位占8字节),自行运行时数据:哈希值,GC分代年龄,锁状态标志,线程持有锁,偏向线程ID,偏向时间戳。

从图可以看到分代年龄是4bit,最大是15,所以他的分代年龄不能超过15。

klass Pointer:

有klass Pointer类型指针(开启压缩占4字节,关闭压缩占8字节),类的元数据指针。

前面说了:一个对象new出来放在堆里,这时候对象头有一个klass Pointer指向方法区(元空间)的类的元素信息。(这里不是class,kclass是c++底层实现的)

数组:

数组长度(4个字节,只有数组才有)

打印对象信息我们需要引入这个maven包,如图所示。

Object大概16bytes,offset是偏移量。

前面两行数据存储的就是mark word。

第三行就是klass pointer,size显示8bytes

第四行是object alignment,对齐则就是填充padding,保证对象是8bytes的整数倍。

前面三行原本是12个字节,但因为对齐,所以多了4个字节,保证object是8的整数倍,这样计算可以保证计算机效率最高。

数组前面两行也是mark word。

第三行还是klass pointer。

第四行则是我们数组的长度,显示4个字节。

于是对齐就是0,因为已经是16个字节,不需要凑整为8的整数倍。

对象前面两行也是mark word。

第三行还是klass pointer。

第四行int类型默认4个字节

Byte类型b则是一个字节

字节会先内部对齐

之后则是name和object的对象默认都是4个字节

最后再次对齐成为8的倍数,28+4

指针压缩是什么?

前面说了klass没开启压缩是8个字节,开启是4个字节,那么我们刚打印的都是4个字节,为什么呢,因为jdk1.6之后默认都是指针压缩后的。

--XX:+UseCompressedOops(默认开启的)

--XX:-UseCompressedOops关闭命令

5、执行方法

前面说了初始化会为0和null,这时候才会赋值代码里真实的值。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端从入门到精通 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据保险箱
数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档