说一下Java对象的创建过程
Java对象的创建过程一共分为五个步骤:
1、当创建一个对象的时候,JVM 会去常量池中找该类的符号引用,并且检查该类还有没有被 JVM 加载过,如果没有,则进行类的加载过程。
2、在类加载检查通过之后,JVM 开始在 Java 堆中为对象分配具体的内存空间。
3、对象内存分配完成之后,JVM 会给 Java 对象除了对象头之外的示例数据初始化零值。这就是为什么类变量可以不需要手动进行初始化值,就可以使用的原因,而局部变量需要手动赋值才可以使用。
4、设置对象头,给对象头设置一些信息。比如:对象的哈希吗,对象的 GC 分代年龄,指向类的元数据信息的指针,锁信息等等。
5、执行对象的 init 方法,比如执行普通代码块,构造函数等等。
简单聊聊 JVM 内存分配与回收
Java 内存管理主要是针对对象内存的分配和对象内存的回收。
Java 堆是垃圾收集管理的主要区域,因此 Java 堆也被称作 GC 堆。从垃圾回收的角度,目前的垃圾回收器基本上采用的是分代垃圾收集算法,所以 Java 堆也被划分为多个区域。
Java 堆主要分为新生代和老年代,其中新生代又分为 Eden
空间、From Survivor
、To Survivor
等空间。
1、当创建一个新的对象,对象会被分配到 Eden 空间。
2、如果该对象经历过一次垃圾回收之后,该对象还存活,则会将该对象移动到 From Survivor
或者 To Survivor
区域,并且该对象的年龄变为 1 岁。
3、该对象在 From Survivor
或者 To Survivor
区域 每经过一次垃圾回收,年龄就会 +1 。当对象年龄达到晋升老年代区域的阈值的时候,就会将该对象移动至老年代区域。晋升老年代区域的阈值默认为 15 岁,并且该阈值可以通过参数 -XX:MaxTenuringThreshold
来设置。
说一下堆内存中对象的分配的基本策略
1、对象优先分配在 Eden 区域,当 eden 区没有足够空间进行分配时,虚拟机将发起一次 Minor GC 。
2、大对象直接进入老年代,比如字符串和数组。
3、年龄大的对象,进入老年区。对象在 Eden 区域经过一次 GC ,移动到Survivor 区域,年龄为1岁,然后每经过一次 GC ,对象年龄 +1 ,当对象年龄达到晋升老年代区域的阈值年龄时,对象移动到老年代,晋升老年代区域的阈值年龄默认为 15 岁,并且该阈值可以通过参数 -XX:MaxTenuringThreshold
来设置。
如何判断对象是否死亡
1、引用计数法
给对象添加一个引用计数器,每当有一个地方引用该对象,则计数器 +1 ,如果引用失效,则计数器 -1 ,计数器为 0 的对象将不可以再被使用,即被判定为死亡。
2、可达性分析算法
这个算法是通过一系列被称作 GC Roots
的对象作为起点,从这些节点依次向下搜索,该节点走过的路径被称为引用链,凡是在引用链上的对象,则对象可用,如果一个对象没有到达 GC Roots
的引用链相连接的话,则说明该对象不可用,判断为死亡。
如何判断一个常量是废弃常量
当一个常量没有被任何变量所引用的时候,就将该变量称为废弃变量,这时如果发生 GC ,并且内存不足的时候,就会将废弃变量回收。
如何判断一个类是无用的类
满足以下三点,该类则被称作无用的类:
1、该类的所有对象实例都已经被回收。
2、加载该类的 ClassLoader
被回收。
3、该类对应的 java.lang.Class
对象在任何地方都没有被引用,程序无法通过反射访问该类的方法。