JVM的演变

发布时间:2024年01月18日

Java虚拟机(JVM)是Java语言的核心组成部分,它负责将Java字节码转换为机器码并执行。随着时间的推移,JVM在不同版本的JDK中经历了许多演变和改进。本文将深入浅出地介绍从JDK 7到JDK 21不同主流版本的JVM结构变化及其特性,帮助你编写更适合的Java代码。

JDK 7

在JDK 7中,JVM引入了一些重要的特性和改进。

1. G1垃圾收集器

JDK 7引入了G1(Garbage-First)垃圾收集器,它是一种基于区域的垃圾收集器,旨在提供更好的吞吐量和更低的停顿时间。G1垃圾收集器使用了一种称为"分代并发"的算法,可以在多个CPU核心上并发地执行垃圾收集操作,从而减少了应用程序的停顿时间。

// 启用G1垃圾收集器
java -XX:+UseG1GC MyApp

2. 字符串拼接优化

在JDK 7之前,字符串拼接通常使用+操作符,这会导致创建大量的中间字符串对象。JDK 7引入了StringBuilder的自动优化,当使用+操作符拼接字符串时,JVM会自动将其转换为StringBuilder的方式,避免了中间字符串对象的创建。

String name = "John";
int age = 25;
String message = "My name is " + name + " and I'm " + age + " years old.";

3. InvokeDynamic指令

JDK 7引入了InvokeDynamic指令,它是一种动态方法调用的机制,可以在运行时动态地解析和绑定方法。这为动态语言和函数式编程提供了更好的支持,例如在Java 8中引入的Lambda表达式和方法引用。

// 动态调用方法
MethodHandle mh = MethodHandles.lookup().findVirtual(MyClass.class, "myMethod", MethodType.methodType(void.class));
mh.invoke(myObject);

JDK 8

JDK 8进一步改进了JVM,并引入了一些重要的特性。

1. Lambda表达式

JDK 8引入了Lambda表达式,它是一种简洁而强大的语法,用于表示匿名函数。Lambda表达式通过使用invokedynamic指令在运行时动态地创建函数对象。

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
       .filter(n -> n % 2 == 0)
       .forEach(System.out::println);

2. PermGen空间移除

在JDK 8中,永久代(PermGen)被移除,取而代之的是元空间(Metaspace)。元空间是堆外的本地内存,用于存储类的元数据信息。这种改变解决了永久代容易出现内存溢出的问题,并提供了更好的性能和可扩展性。

3. 默认方法

JDK 8引入了默认方法(Default Method),允许在接口中定义具有默认实现的方法。这为接口的演化提供了更大的灵活性,可以向现有的接口添加新的方法,而不会破坏已有的实现类。

public interface MyInterface {
    default void myMethod() {
        System.out.println("Default implementation");
    }
}

public class MyClass implements MyInterface {
    // 不需要实现myMethod,使用默认实现
}

MyClass obj = new MyClass();
obj.myMethod(); // 输出: Default implementation

JDK 11

JDK 11引入了一些重要的改进和新特性。

1. Epsilon垃圾收集器

JDK 11引入了Epsilon垃圾收集器,它是一种无操作的垃圾收集器,用于测试和性能调优。Epsilon垃圾收集器不执行任何垃圾收集操作,只是简单地分配内存并丢弃它,适用于不需要垃圾收集的场景。

// 启用Epsilon垃圾收集器
java -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC MyApp

2. 单文件源代码执行

JDK 11引入了单文件源代码执行的功能,允许直接执行单个Java源文件,而无需显式编译为字节码文件。这对于编写简单的脚本和小型应用程序非常方便。

// 直接执行单个Java源文件
java HelloWorld.java

3. ZGC垃圾收集器

JDK 11引入了ZGC垃圾收集器,它是一种低延迟的垃圾收集器,旨在处理大内存和超大内存的场景。ZGC垃圾收集器使用了一种称为"可并发压缩"的算法,可以在非常短的停顿时间内执行垃圾收集操作。

// 启用ZGC垃圾收集器
java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC MyApp

JDK 17

JDK 17继续改进了JVM并引入了一些新特性。

1. 基于嵌套的访问控制

JDK 17引入了基于嵌套的访问控制,允许在类和接口中定义嵌套的访问控制上下文。这提供了更细粒度的访问控制,可以更好地封装和保护类的内部实现细节。

public class Outer {
    private int outerPrivateField;

    public class Inner {
        public void accessOuter() {
            System.out.println(outerPrivateField);
        }
    }
}

2. 静态嵌套类中的嵌套接口

JDK 17允许在静态嵌套类中定义嵌套接口。这使得代码更具可读性和组织性,可以更好地表示类之间的关系。

public class Outer {
    public static class Nested {
        public interface Inner {
            void doSomething();
        }
    }
}

Outer.Nested.Inner obj = new Outer.Nested.Inner() {
    public void doSomething() {
        System.out.println("Doing something");
    }
};

obj.doSomething(); // 输出: Doing something

3. 基于事件的垃圾收集器接口

JDK 17引入了基于事件的垃圾收集器接口,允许开发人员监视和控制垃圾收集器的行为。这为性能调优和故障排查提供了更多的工具和灵活性。

// 注册垃圾收集器事件监听器
GarbageCollectorMXBean gcBean = ManagementFactory.getGarbageCollectorMXBeans().get(0);
gcBean.addGarbageCollectionNotificationListener(new GarbageCollectionNotificationListener() {
    public void handleNotification(GarbageCollectionNotificationInfo info, Object handback) {
        System.out.println("GC event: " + info.getGcAction());
    }
}, null);

JDK 21

JDK 21是目前最新的JDK版本,它继续改进了JVM并引入了一些新特性。

1. 分代ZGC

分代 ZGC(Generational ZGC)在?hotspot/gc?包中。通过扩展Z垃圾回收器(ZGC)来维护年轻对象和年老对象的独立生成,从而提高应用程序性能。这将使ZGC能够更频繁地收集年轻对象——这些对象往往英年早逝。

2. 引入虚拟线程

将虚拟线程(Virtual Threads)引入Java平台。虚拟线程是轻量级线程,可以显著减少编写、维护和观察高吞吐量并发应用程序的工作量。

3.禁止动态加载代理

将代理动态加载到正在运行的JVM中时发出警告。这些警告旨在让用户为将来的版本做好准备,该版本默认情况下不允许动态加载代理,以提高默认情况下的完整性。在启动时加载代理的可服务性工具不会导致在任何版本中发出警告。

总结

本文深入浅出地介绍了JVM从JDK 7到JDK 21不同主流版本的演变和特性。我们学习了每个版本中的重要改进,包括垃圾收集器的改进、新的语言特性和性能优化。了解JVM的演变可以帮助我们编写更适合的Java代码,并充分利用JVM的功能和性能。

希望本文能够帮助你理解JVM的演变和特性,并在实际项目中应用这些知识。如果你对JVM的更多细节和深入内容感兴趣,可以查阅官方文档和其他相关资源进行深入学习。

参考资料:

文章来源:https://blog.csdn.net/xiaohui249/article/details/135666093
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。