百度面试题解析:新生代分区、垃圾回收算法、虚拟机栈和类加载(四)
#### 23. 新生代为什么又分为Eden、S0和S1?
JVM的堆被分为三个主要区域:Eden区、S0区(Survivor 0区)和S1区(Survivor 1区)。这三个区域的划分是为了优化内存管理和垃圾回收(GC)过程,尤其是在新生代区域,目的是减少对象分配时的停顿时间,提高性能。
- **Eden区**:
Eden区是新生代区域的主要部分,所有新创建的对象都分配在这里。当Eden区满了,JVM会触发一次垃圾回收,即**Minor GC**。通常,大部分新对象都在GC后被清除,因此Eden区的对象存活时间短暂。
- **S0区和S1区(Survivor区)**:
新生代有两个Survivor区,S0和S1。它们用于存放Eden区存活下来的对象。当Eden区垃圾回收后,存活的对象会被移动到其中一个Survivor区。Survivor区主要的作用是存活对象的转移和进一步筛选。
- **S0区和S1区的交换**:
在每次垃圾回收时,S0和S1区会交换角色。比如,如果Eden区回收后,存活的对象会移到S0区,那么下一次GC时,S0区的对象可能会移动到S1区,反之亦然。
- **优点**:
新生代分为Eden和两个Survivor区的目的是通过**多次复制**,有效地管理对象的存活。对象只有在多次GC后才有可能晋升到老年代,从而提高了GC效率,减少了长时间停顿的情况。
#### 24. 标记算法?
**标记算法**是最基础的垃圾回收算法,其主要步骤包括:
1. **标记阶段**:
从GC Roots(垃圾回收根对象)开始,标记所有可以到达的对象。这个阶段会遍历整个对象图,标记出所有存活的对象。
2. **清理阶段**:
清理所有没有被标记的对象,这些对象被认为是不可达的、可以回收的。
标记算法的优点是简单,但缺点是需要进行两次遍历,而且会存在“内存碎片”的问题,即对象清理后会留下不连续的内存空间,影响后续的内存分配。
#### 25. 可达性分析工作原理?哪些可以作为GC Roots根?
**可达性分析**是垃圾回收算法中的一种核心思想。它通过从GC Roots对象出发,遍历所有能够直接或间接到达的对象,并标记这些对象为“可达”对象。那些无法通过GC Roots访问到的对象就会被认为是不可达的,并最终被回收。
**GC Roots** 是垃圾回收的起点,通常包括以下几种对象:
1. **虚拟机栈中的引用**:
每个线程的虚拟机栈中可能会保存一些局部变量引用(例如方法参数、局部变量等)。这些引用属于GC Roots的一部分。
2. **静态字段**:
类的静态字段保存在方法区中,它们通常是常驻内存的,因此类的静态字段也可以作为GC Roots。
3. **活动线程**:
当前正在运行的线程和它们的栈帧中的局部变量引用也可以作为GC Roots。
4. **JNI引用**:
JNI(Java Native Interface)中的引用对象也属于GC Roots。
通过可达性分析,JVM能够确定哪些对象是“活跃”的,哪些是“不再使用”的。
#### 26. 虚拟机栈局部变量表存什么?
**虚拟机栈**用于存储方法调用时的栈帧,每个方法在调用时都会创建一个栈帧。栈帧中包含多个部分,其中最重要的是**局部变量表**。
**局部变量表存储的内容**:
- **方法的参数**:
每个方法的参数会被存储在局部变量表中,按顺序存放。基本数据类型(如`int`、`float`等)会占一个槽位,引用类型(如对象)也占一个槽位。
- **局部变量**:
局部变量包括方法中的局部变量和临时变量。这些变量仅在方法调用过程中有效,当方法结束后,它们会被销毁。
- **操作数栈的指针**:
每个栈帧有一个指向操作数栈的指针。操作数栈用于存储方法执行过程中计算的中间结果。
#### 27. class加载过程讲一下?
**类加载过程**是JVM将类文件(.class文件)加载到JVM内存中的过程,主要包括以下几个步骤:
1. **加载(Load)**:
类加载器读取.class文件,将它们加载到内存中,生成`Class`对象。这个过程由**类加载器**(ClassLoader)负责。
2. **验证(Verify)**:
验证加载的类是否符合JVM的规范,确保字节码文件不会破坏JVM的安全性和完整性。
3. **准备(Prepare)**:
为类的静态变量分配内存并设置默认值。这个过程是为了初始化类的静态变量,保证类的静态字段有默认值。
4. **解析(Resolve)**:
解析符号引用,即把类中的符号引用(如类、方法、字段)转换成直接引用。比如将类的符号引用转化为内存中的地址。
5. **初始化(Initialize)**:
初始化阶段,类的静态变量会被赋予实际的值,静态代码块也会被执行。这个阶段只会发生一次。
#### 28. new对象,发生了什么过程?
在Java中,使用`new`关键字创建对象时,JVM会执行一系列操作:
1. **分配内存**:
首先,JVM会为新对象分配内存空间。内存分配的位置通常在堆内存中。
2. **初始化零值**:
在分配内存后,JVM会给对象的字段设置默认值。例如,数值类型的字段会被设置为`0`,引用类型的字段会被设置为`null`。
3. **调用构造方法**:
一旦内存分配和字段初始化完成,JVM会调用该类的构造方法进行初始化。构造方法可以有初始化逻辑,例如为对象字段赋具体值。
4. **返回对象的引用**:
最后,`new`关键字会返回新创建的对象的引用,供后续使用。
在整个过程中,如果类没有被加载过,JVM会触发类加载机制,加载该类并执行相关步骤。通过`new`关键字创建的对象最终会存放在堆内存中,且所有的对象都会经历垃圾回收过程。