Skip to content

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);
          }
      }
    • 执行引擎

      • 解释器:逐行解释执行字节码,适合短小的程序,但执行效率较低。
      • 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;
          }
      }
  • 垃圾回收算法的基本原理

    • 标记-清除算法:首先标记所有需要回收的对象,然后清除这些对象。优点是实现简单,但会产生内存碎片。

    • 复制算法:将内存分为两块,每次只使用一块。当一块内存用满时,将存活的对象复制到另一块内存中,清空当前块。优点是避免了内存碎片,但内存利用率较低。

    • 标记-整理算法:类似于标记-清除,但在清除后将存活的对象整理到内存的一端,避免了内存碎片。

    • 分代收集算法:将堆内存分为新生代和老年代。新生代使用复制算法,老年代使用标记-清除或标记-整理算法。根据对象的存活时间进行分代管理,提高了垃圾回收的效率。

      示例

      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 的内部机制让我在性能调优方面有了更深的认识。通过学习类加载和内存管理,我能够更有效地识别和解决性能瓶颈。