当前位置:网站首页>JVM层次上的对象的创建过程和内存布局
JVM层次上的对象的创建过程和内存布局
2022-06-27 08:06:00 【小月亮6】
Java种有5种创建新对象的方式
- 调用关键字new
这种也是我们一开始最常见的方式:
person p1 = new person("zs", 20, "男");
- 使用反射机制
反射机制有两种方法,一种是使用Class类的newInstance方法。
调用无参的构造方法。
person p2;
try {
p2=(person)Class.forName("ioText/tex2").newInstance();
//或者也可以
p2=person.getClass().newInstance();
}catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
另外一种方法是调用Constructor类中的newInstance方法。java.lang.reflect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个方法调用有参数的和私有的构造函数。
try {
Constructor<person> c=person.class.getConstructor();
person p3=c.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
- 调用Clone()方法
再调用Clone方法前,要注意的是我们要先实现Cloneable接口,并且定义clone()方法。
person p = new person("zs", 20, "男");
person p1= (person)p.clone();
- 反序列化方法
当我们序列化或者反序列化一个对象,jvm会给我们创建一个单独的对象。在我们反序列化时,jvm创建对象并不会调用构造函数。在使用反序列化前,我们要像Clone()方法一样,实现Serializable接口。
try {
ObjectInputStream in =
new ObjectInputStream(new FileInputStream("D:/java2/ioText/text2.txt"));
person p = (person) in.readObject();
System.out.println(p);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
我们对五种创建方法进行对比,会发现方法1,2,3用构造函数创建对象,方法4,5没有调用构造函数。
| 创建方式 | 是否调用构造函数 |
|---|---|
| 使用new关键字 | 调用了构造函数 |
| 使用Constructor类的newInstance方法 | 调用了构造函数 |
| 使用Class类的newInstance方法 | 调用了构造函数 |
| 使用clone方法 | 没有调用构造函数 |
| 使用反序列化 | 没有调用构造函数 |
上面是转发于这篇文章

对象创建的六个步骤
1.判断对象对应的类是否加载、链接、初始化
虚拟机遇到一条new指令,首先去检查这个指令的参数能否在Metaspace的常量池中 定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和 初始化。(即判断类元信息是否存在)。如果没有,那么在双亲委派模式下,使用当 前类加载器以classLoader+包名+类名为Key进行查找对应的.class文件。如果没 有找到文件,则拋出ClassNotFoundException异常,如果找到,则进行类加载, 并生成对应的Class类对象
2.为对象分配内存
首先计算对象占用空间大小,接着在堆中划分一块内存给新对象。
如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小。
如果内存规整,使用指针碰撞
如果内存是规整的,那么虚拟机将采用的是指针碰撞法(Bump The Pointer)来为对象分配 内存。意思是所有用过的内存在一边,空闲的内存在另外一边,中间放着一个指针作为分界 点的指示器,分配内存就仅仅是把指针向空闲那边挪动一段与对象大小相等的距离罢了。如 果垃圾收集器选择的是Serial、ParNew这种基于压缩算法的,虚拟机采用这种分配方式。 一般使用带有compact(整理)过程的收集器时,使用指针碰撞。
如果内存不规整,虚拟机需要维护一个列表,使用空闲列表分配
如果内存不是规整的,已使用的内存和未使用的内存相互交错,那么虚拟机将采用的是空闲 列表法来为对象分配内存。意思是虚拟机维护了一个列表,记录上哪些内存块是可用的,再 分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。这种分 配方式成为“空闲列表(Free List)”。
说明:选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集 器是否带有压缩整理功能决定。
3.处理并发安全问题
在分配内存空间时,另外一个问题是及时保证new对象时候的线程安全性:创建对象是非常 频繁的操作,虚拟机需要解决并发问题。虚拟机采用了两种方式解决并发问题: CAS ( Compare And Swap)失败重试、区域加锁:保证指针更新操作的原子性;.TLAB把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中 预先分配一小块内存,称为本地线程分配缓冲区,(TLAB , Thread Local Allocation Buffer)虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。
4.初始化分配到的空间
内存分配结束,虚拟机将分配到的内存空间都初始化为零值(不包括对象头)。这一步保 证了对象的实例字段在Java代码中可以不用赋初始值就可以直接使用,程序能访问到这些 字段的数据类型所对应的零值。
5.设置对象的对象头
将对象的所属类(即类的元数据信息)、对象的HashCode和对象的GC信息、锁信息等数 据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现。
6.执行init方法进行初始化
在Java程序的视角看来,初始化才正式开始。初始化成员变量,执行实例化代码块,调 用类的构造方法,并把堆内对象的首地址赋值给引用变量。
因此一般来说(由字节码中是否跟随有invokespecial指令所决定),new指令之后会接 着就是执行方法,把对象按照程序员的意愿进行初始化,这样一一个真正可用的对象才算完 全创建出来。
对象的内存布局

public class Customer {
int id = 1001;
String name;
Account acct;
{
name = "匿名客户";
}
public Customer(){
acct = new Account();
}
}
class Account{
}public class CustomerTest {
public static void main(String[] args) {
Customer cust = new Customer();
}
}

访问对象定位

总体思路为 栈帧中reference访问堆区然后通过元数据指针访问方法区:

具体实现有两种:

1.句柄访问:

2.直接指针(hotspot采用)优点多一些

边栏推荐
- [c++ primer notes] Chapter 4 expression
- Coal crusher
- js用while循环计算假如投资多年的利率为5%,试求从1000块增长到5000块,需要花费多少年
- 【c ++ primer 笔记】第4章 表达式
- 盲测调查显示女码农比男码农更优秀
- Publications under nature, science and cell
- [batch dos-cmd command - summary and summary] - parameters%0,%1,%2,%[0-9],%0-9 in the batch command and batch command parameter position switching command shift, operator% usage in the DOS command
- LVGL GUI GUIDER移植代码到STM32
- 洛谷刷题心得记录
- Game asset reuse: a new way to find required game assets faster
猜你喜欢

L'enquête en aveugle a montré que les femmes étaient meilleures que les hommes.

Cookie encryption 6

Eight misunderstandings, broken one by one (final): the cloud is difficult to expand, the customization is poor, and the administrator will lose control?

js来打印1-100间的质数并求总个数优化版

lvgl 说明3关于lvgl guider的使用

(原创)自定义Drawable
![[batch dos-cmd command - summary and summary] - map folder to virtual disk - subst](/img/09/cd12c276392d3465dce1909d0f86a6.png)
[batch dos-cmd command - summary and summary] - map folder to virtual disk - subst

SPARQL basic introductory exercise

【13. 二进制中1的个数、位运算】

關聯GIS:條條道路通UE5城
随机推荐
野風藥業IPO被終止:曾擬募資5.4億 實控人俞蘠曾進行P2P投資
Binary tree structure and heap structure foundation
Windows下mysql-8下载、安装、配置教程
SPARQL基础入门练习
The IPO of Yefeng pharmaceutical was terminated: Yu Feng, the actual controller who had planned to raise 540million yuan, made P2P investment
准备好迁移上云了?请收下这份迁移步骤清单
Coggle 30 days of ML July competition learning
[10. difference]
Import and export database related tables from the win command line
SQL Sever column name or number of supplied values does not match the table definition
JS print 99 multiplication table
js中输入三个值,并且由小到大输出
js求所有水仙花数
【批处理DOS-CMD命令-汇总和小结】-批处理命令中的参数%0、%1、%2、%[0-9]、%0-9和批处理命令参数位置切换命令shift,dos命令中操作符%用法
Ue5 magic power - POI solution
[batch dos-cmd command - summary and summary] - how to distinguish the internal command and external command of CMD, and the difference between CMD command and run (win+r) command,
js中判断奇偶的函数,求圆面积的函数
【批处理DOS-CMD命令-汇总和小结】-输出/显示命令——echo
Speech signal feature extraction process: input speech signal - framing, pre emphasis, windowing, fft- > STFT spectrum (including amplitude and phase) - square the complex number - > amplitude spectru
The 6th Blue Bridge Cup