运行时常量池
运行时常量池是 JVM 在运行时动态生成的一块内存区域,用于存储编译期生成的各种字面量和符号引用。在 JDK 8 之前,运行时常量池位于方法区中,而在 JDK 8 及之后版本,它被移到了堆中。运行时常量池不仅包含 Class 文件中的常量池数据,还包括 JVM 运行期间生成的一些常量。
标记清除算法、标记整理算法和标记复制算法
- 标记清除算法: 首先标记所有需要回收的对象,然后对标记的对象进行清除。这种算法会产生不连续的内存碎片,影响内存的分配效率。
- 标记整理算法: 类似于标记清除算法,但在标记完成后会对存活对象进行整理,使它们在内存中变得连续。这样可以避免内存碎片问题。
- 标记复制算法: 将内存空间划分为两个区域,一部分用于存储对象,另一部分保持空闲。当对象存活时,将其复制到空闲区域,然后清理已使用区域。这样可以避免内存碎片,但是需要额外的空间用于复制对象。
分代收集算法
分代收集算法根据对象的存活周期将堆内存划分为不同的区域,一般分为新生代和老年代。新生代使用复制算法,老年代使用标记整理或标记清除算法。这样可以根据不同区域的特点采用更适合的垃圾回收算法,提高效率。
Serial、ParNew、Parallel Scavenge、CMS、G1 收集器简述
- Serial 收集器: 单线程,新生代使用标记复制算法,老年代使用标记整理算法,适用于单核 CPU 环境。
- ParNew 收集器: 多线程版本的 Serial 收集器,新生代使用标记复制算法,老年代使用标记整理算法,适用于多核 CPU 环境。
- Parallel Scavenge 收集器: 多线程,注重吞吐量,适用于后台运算等对系统资源要求不敏感的场景。
- CMS(Concurrent Mark-Sweep)收集器: 以最短的停顿时间为目标,采用并发标记和并发清除算法,适用于对系统响应时间有要求的场景。
- G1(Garbage First)收集器: 将堆内存分为多个大小相等的区域,具有高灵活性,可通过设置参数调整吞吐量和停顿时间,适用于大内存应用和对低延迟有要求的场景。
Minor GC 和 Full GC
- Minor GC: 发生在新生代的垃圾收集,主要回收新生代,频繁且速度较快。
- Full GC: 清理整个堆,包括新生代、老年代和永久代(或元空间)。发生 Full GC 通常伴随着较长的停顿时间,对系统影响较大。
内存分配策略
- 大多数对象在新生代 Eden 区分配,当 Eden 满时触发 Minor GC。
- 大对象直接进入老年代。
- 对象优先在 Eden 区分配,如果经过一次 Minor GC 后仍然存活且能容纳,则进入 Survivor 区;否则直接进入老年代。
- 长期存活的对象将进入老年代。
JVM 类加载过程
- 加载(Loading): 通过类的全限定名获取类的二进制字节流。
- 验证(Verification): 对字节流进行各种验证,确保符合 JVM 规范。
- 准备(Preparation): 为类变量分配内存并设置默认初始值。
- 解析(Resolution): 将符号引用转化为直接引用。
- 初始化(Initialization): 执行类构造器
<clinit>方法,初始化类变量和静态代码块。
类加载器和双亲委派机制
- BootstrapClassLoader: 加载 Java 核心类库,由 C++ 编写。
- ExtensionClassLoader: 加载扩展类库,由 Java 编写。
- AppClassLoader: 加载应用程序类,由 Java 编写。
双亲委派机制:一个类加载器在加载类时,先将加载请求委派给父类加载器,一直委派到启动类加载器,只有在父类加载器无法加载时才尝试自己加载。这样确保类加载的一致性和避免类的重复加载。
破坏双亲委派机制
破坏双亲委派机制的方式主要是重写 loadClass 方法,不调用父类加载器,直接自己加载类。这样会导致类的重复加载和破坏类加载的一致性。