2021年9月15日

ut金牌美女_new一个对象的时候发生了什么?

作者 adminer

专注于Java领域的优秀技术,欢迎关注

作者:湖人总冠军

一、引言

如你所知,Java是面向对象的编程语言。我们平常在写代码的时候也是在不停的操作各种对象,那么当你在写出User user = new User();这样一行代码的时候,JVM都做了些什么呢?

二、了解对象

1、内存布局

在Hotspot虚拟机中一个对象的内存布局分为三个部分:对象头、实例数据、对齐填充。

受众头部还有两部分信息,第一部分用于存储受众自身的运行数据(HashCode、GC分代年龄、锁定状态标志等)。另一部分是类型指针,指向其类型的元数据,虚拟机通过该指针确定该对象是哪个类型的例子(使用句柄池的方式不存在)。如果是数组还会有一个记录数组长度的如下表所示:

Mark Word是一个非固定的数据结构以便在极小的空间内存储尽量多的信息,ut金牌美女它会根据对象的状态复用自己的存储空间。各状态下的存储内容如下表所示:

实例数据部分是真正存储的有效信息,是代码中定义的各种类型的字段内容。ut金牌美女无论是父亲继承的还是子女的。对齐填充不是必须的,只是起占位符的作用,HotSpot虚拟机要求对象的起始地址必须是8字节的整数倍。

2、对象访问

Java程序中我们操作一个对象是指向该对象的引用。众所周知,方有堆积物,ut金牌美女这个引用存在虚拟堆积物。那么,引用是用什么方法定位对象的位置呢?

直接指针法(HotSpot实现):引用中直接存储的是堆积对象的地址。优点是一次定位速度快,缺点是对象移动(GC时对象移动)引用本身需要修改。

句柄法:Java堆中分为句柄池的一部分,引用保存对象的句柄地址,句柄中包含对象实例和类型的具体位置信息。优点是对象移动只会改变句柄中的实例数据指针,ut极品美女西厢缺点是两次定位。

三、创建对象流程

以上介绍对象的基本信息,现在就创建对象的流程进行说明。

当虚拟机会遇到new命令时,检查该命令的参数是否可以在常量池中定位为一种符号引用,检查代表的类别是否被类加载。如果没有加载,必须首先执行这种加载。类加载检查合格后,虚拟机将为新对象分配内存,对象所需内存的大小可在类加载后确定。内存分配完成后,虚拟机需要将对象初始化为零值,保证对象实例变量在代码中不赋予初始值即可直接使用。类变量在类加载的准备阶段初始化为零值。对受众头部进行必要信息的设置,ut金牌美女如如如何找到类别的元数据信息、受众的HashCode、GC替代年龄等。经过上述操作,产生了新的对象,但<init>方法尚未执行,所有字段为零。此时,ut金牌美女必须执行<init>方法(结构方法)根据程序员的意愿初始化对象。类变量的初始化操作在类加载的初始化阶段<clinit>方法完成

分配存储器有

Java堆积存储器规则(使用标记整理或带压缩的垃圾收集器),使用指针指向空闲位置,分配存储器将指针移动与分配大小相等的距离存储器不规则(使用标记清除的垃圾收集器)

无法找到足够的内存时会触发一次GC

分配内存时并发问题解决方案:

对分配内存空间的动作进行同步操作—采用CAS失败重试的方式保证更新操作的原子性。每个线程在堆中预先分配一块小内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB),哪个线程要分配内存就在它的TLAB上分配,只有TLAB用完并分配新的TLAB时才需要同步锁定。通过-XX:/-UseTLAB参数设置。

四、创建对象命令重新排序问题

A=newa()

new一个对象的简单分解动作:

分配对象的存储空间初始化对象设置引用指向分配的存储地址

其中2、3两个步骤发生命令重新排序,多线程序在初始化前访问对象发生问题,单例模式的双重检查锁模式存在这个问题。使用volatile,禁止命令重新排序解决问题

资料来源:挖掘金:https://juejin.im/post/5da971216fb9a04e17209328