对象创建和内存分配
Java中类创建是在平常不过的操作了,但是一个类的创建到底经历 了哪些过程呢?
对象创建
创建方法
-
使用关键字new一个对象
-
使用反射机制
User user = (User)Class.forName("xxx.xxx.User").newInstance(); User user = User.class.newInstance();
-
使用clone方法
-
反序列化
创建过程
在Java中,对象的创建是通过关键字new来实现的。
User user = new User();
JVM在执行以下步骤来创建一个对象:
- 类加载:将Java类的字节码从外部存储到内存中,并在JVM中创建对应的class对象。
- 分配内存:JVM会对对象分配内存。
- 初始化:一旦对象内存分配完成,JVM将调用丢向的构造器来执行对象的初始化。
- 设置对象头:初始化对象后,JVM要对对象进行必要的设置,例如元数据谢谢,哈希码,分代年龄等信息。
- init方法:按照程序进行初始化,及对对象赋值,与上面第三步初始化(零赋值)是不同的。
内存分配
分配策略
首先,提出一个这样的问题;
Java中new一个对象,存在哪里?对象的引用存在哪里?static修饰的对象存在哪里?
堆内存: 大多数Java对象都存储在堆内存中。堆内存是JVM的主要内存池,用于存储对象的实例数据。对象在堆上分配,而堆的管理是由垃圾回收器负责的。当对象不再被引用时,垃圾回收器会自动回收堆内存中的对象。
栈内存: 栈内存用于存储局部变量和方法调用信息。基本数据类型和对象引用通常存储在栈上。栈内存的分配和释放非常快速,因为它们仅在方法的生命周期内存在。
方法区: 方法区用于存储类的元数据、静态字段和方法。它也包含字符串常量池和运行时常量池。方法区的内存分配由JVM控制,并在类加载和卸载时发挥重要作用。
分配方法
-
指针碰撞
当分配新对象的时候,JVM会维护一个指针,指向下一个可用的内存位置,分配新对象时,JVM将指针向前移动,以便在堆上分配新对象的内存空间。
-
空闲列表
通过维护一个空闲列表,当需要分配新对象时,JVM会在空闲列表中寻找一个合适的内存块,将其分配给新对象。然后更新空闲列表。
分配过程
首先,提出一个问题?
什么情况下,对象会分配到栈内存上?
现在来回答上面问题,对象一般是在堆上进行分配的,但是JVM为了减少对象在堆上分配的数量,JVM进行逃逸分析确认该对象会不会对外部访问,如果不会则将该对象分配到栈内存上面去。出栈的时候将该对象销毁,减轻垃圾回收的负担。
对象逃逸分析
对象逃逸分析是一种用于对象在其生命周期中是否逃逸出方法的作用域的优化技术。当对象没有逃逸时,则分配在堆上;对象逃逸了,则直接分配到栈上,减少堆对象的数量以及垃圾回收负担。
举个例子:
public void createObject() {
// 在方法内部创建一个对象,并将其赋值给成员变量
obj = new Object();
}
public Object getObject() {
// 返回对象的引用
return obj;
}
上面代码中,createObject()会出现对象逃逸,getObject()没有出现对象逃逸。