Java虚拟机
主要内容
JVM 的构成:
类加载器:
- 引导类加载器:负责加载 Java 核心类库(如
java.lang
包)。它是最顶层的类加载器,使用 C++ 编写,无法被 Java 代码直接访问。 - 扩展类加载器:负责加载 JDK 的扩展库,通常位于
jre/lib/ext
目录下。它的父类是引导类加载器。 - 应用类加载器:负责加载用户类路径下的类(如项目中的
.class
文件)。它的父类是扩展类加载器。 - 双亲委派模型:类加载器采用双亲委派模型,确保类的唯一性和安全性。即当一个类加载器接收到类加载请求时,它会先委派给父类加载器进行加载,只有在父类加载器无法找到该类时,才会自己加载。
示例:
java// 示例代码:自定义类加载器 public class MyClassLoader extends ClassLoader { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 自定义加载逻辑 return super.findClass(name); } }
- 引导类加载器:负责加载 Java 核心类库(如
执行引擎:
- 解释器:逐行解释执行字节码,适合短小的程序,但执行效率较低。
- JIT(即时编译器):将热点代码(频繁执行的代码)编译为本地机器码,以提高执行效率。JIT 编译器在运行时进行优化,能够根据实际运行情况进行调整。
- 优化技术:JIT 编译器使用多种优化技术,如内联、循环展开和逃逸分析等,以提高代码执行效率。
示例:
java// 示例代码:简单的 Java 程序 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }
内存管理单元:
- 内存区域划分:JVM 的内存管理单元主要分为以下几个区域:
- 方法区:用于存储类的结构信息(如字段、方法、常量池等),以及静态变量和常量。方法区是所有线程共享的内存区域。
- 堆:用于存储所有对象实例和数组。堆是 JVM 中最大的一块内存区域,也是垃圾回收的主要区域。堆内存是所有线程共享的。
- 栈:每个线程都有自己的栈,用于存储局部变量、方法调用的参数和返回值、操作数等。栈内存是线程私有的,随着线程的结束而释放。
- 本地方法栈:用于存储本地方法的相关信息,类似于 Java 栈,但专门用于处理本地方法调用。
- 程序计数器:每个线程都有一个程序计数器,用于记录当前线程所执行的字节码的行号指示器。它是线程私有的。
示例:
java// 示例代码:对象的创建和内存分配 public class MemoryExample { public static void main(String[] args) { // 在堆中分配内存 String str = new String("Hello, JVM!"); // 局部变量在栈中分配内存 int number = 42; } }
- 内存区域划分:JVM 的内存管理单元主要分为以下几个区域:
垃圾回收算法的基本原理:
标记-清除算法:首先标记所有需要回收的对象,然后清除这些对象。优点是实现简单,但会产生内存碎片。
复制算法:将内存分为两块,每次只使用一块。当一块内存用满时,将存活的对象复制到另一块内存中,清空当前块。优点是避免了内存碎片,但内存利用率较低。
标记-整理算法:类似于标记-清除,但在清除后将存活的对象整理到内存的一端,避免了内存碎片。
分代收集算法:将堆内存分为新生代和老年代。新生代使用复制算法,老年代使用标记-清除或标记-整理算法。根据对象的存活时间进行分代管理,提高了垃圾回收的效率。
示例:
java// 示例代码:对象的创建与垃圾回收 public class GarbageCollectionExample { public static void main(String[] args) { for (int i = 0; i < 10000; i++) { String temp = new String("Garbage " + i); } // 此时,temp 对象会被垃圾回收 System.gc(); // 请求 JVM 进行垃圾回收 } }
引用和内存的概念:
引用类型:Java 中的引用分为强引用、软引用、弱引用和虚引用。强引用是最常见的引用类型,JVM 不会回收被强引用的对象。软引用在内存不足时会被回收,弱引用在下一次垃圾回收时会被回收,虚引用则用于跟踪对象的生命周期。
示例:
java// 示例代码:不同类型的引用 public class ReferenceExample { public static void main(String[] args) { // 强引用 String strongRef = new String("Strong Reference"); // 软引用 SoftReference<String> softRef = new SoftReference<>(new String("Soft Reference")); // 弱引用 WeakReference<String> weakRef = new WeakReference<>(new String("Weak Reference")); // 虚引用 PhantomReference<String> phantomRef = new PhantomReference<>(new String("Phantom Reference"), null); } }
内存管理:JVM 的内存管理包括内存分配和回收。对象的创建通常在堆中分配内存,局部变量则在栈中分配。JVM 通过垃圾回收机制自动管理内存,开发者无需手动释放内存,但需要注意避免内存泄漏。
个人感悟
了解 JVM 的内部机制让我在性能调优方面有了更深的认识。通过学习类加载和内存管理,我能够更有效地识别和解决性能瓶颈。