像台湾uu的聊天_new一个对象的时候发生了什么?

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

作者:湖人总冠军

一、引言

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

二、了解对象

1、内存布局

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

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

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

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

2、对象访问

Java程序中我们操作一个对象是指向该对象的引用。我们都知道对象存在堆中,这个引用存在虚拟机栈中。那么,引用是用什么方法定位对象的位置呢?

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

句柄法:Java堆中划分出一部分作为句柄池,引用存储的是对象的句柄地址,而句柄中包括了对象实例和类型的具体位置信息。优点是对象移动只会改变句柄中的实例数据指针,缺点是两次定位。

三、创建对象流程

上面介绍了对象的基本信息,现在来讲一讲创建对象的流程:

当虚拟机遇到一条new指令时,会去检查这个指令的参数能否在常量池中定位到一个类的符号引用,像台湾uu的聊天并检查代表的类是否已经被类加载器加载。如果没有加载,必须首先执行这种加载。类加载检查合格后,虚拟机将为新对象分配内存,对象所需内存的大小可在类加载后确定。内存分配完成后,虚拟机需要将对象初始化为零值,保证对象实例变量在代码中不赋予初始值即可直接使用。类变量在类加载的准备阶段初始化为零值。对受众头部进行必要信息的设置,如如如何找到类别的元数据信息、受众的HashCode、GC替代年龄等。经过上述操作,一个新的对象已经产生,但是<init>方法还没有执行,台湾uu聊天室主题曲像台湾uu的聊天所有的字段都是零值。像台湾uu的聊天这时候需要执行<init>方法(构造方法)把对象按照程序员的意愿进行初始化。类变量的初始化操作在类加载的初始化阶段&lt;clinit&gt;方法完成

分配存储器有

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

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

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

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

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

A=newa()

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

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

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

来源:掘金 链接:https://juejin.im/post/5da971216fb9a04e17209328

发表回复

您的电子邮箱地址不会被公开。