JVM 的发展趋势

140 阅读2分钟

拥抱容器化

New Relic 的数据显示,目前已经有 70% 的 Java 应用是运行在容器中的。为了更好地支持容器化,JVM 逐步放弃了自己原本的平台无关的解决方案,转而拥抱容器化。

容器亲和性

在 JDK 8u131 版本之前,JVM 不具备容器识别能力。这对于已经上云,但还在使用 JDK 8 的 Java 应用来说,存在致命的风险。因为 JVM 会基于宿主机的物理内存来设置堆内存的最大值,而不是基于容器的内存限制,从而导致 JVM 试图使用超出容器限制内存的情况出现,进而被操作系统杀掉,CPU 的使用也存在同样的问题。在 JDK 11、JDK 17 中,JVM 增加了对容器环境的识别能力。JVM 会读取来自操作系统(Docker)和容器管理系统(Kubernetes)提供的信息,来了解它所在的容器的资源限制。JVM 会把这些信息用于堆内存、JIT 编译器的管理中,并且这些新增的功能是默认开启的,无需任何特殊的配置。

AOT 原生镜像编译

从 JDK 9 开始,JVM 支持 AOT(Ahead-Of-Time)编译技术,并在 JDK 11、17 版本中持续增强。AOT 指的是在 JVM 运行之前把代码编译成本地机器码的技术。通过提前将 Java 应用程序编译为即时启动的本地二进制文件,JVM 在无需预热的情况下就可以提供峰值性能。同时,即时编译会产生大量的中间编译代码和相关的数据结构,导致程序占用更多的内存,而 AOT 编译可以在编译时根据具体平台进行优化,减少了这些额外的开销,节省了内存空间。

函数式支持

增强JVM 持续加强对函数式的支持,参照 Go 语言,通过逃逸分析、栈上分配等操作持续提升栈的利用效率。基于函数式编程风格更加强调不可变性和无副作用的特性,产生的垃圾更少。此外,JVM 还引入了 Epsilon 垃圾收集器,这是一个不执行任何垃圾收集的收集器。当应用程序不需要自动内存管理或者为了测试和性能调整而需要关闭垃圾收集时使用。JDK 11 对 Lambda 表达式进行了改进,Lambda 参数可利用 var 关键字声明类型,使 Lambda 表达式的代码更加简洁。这些改进和新增特性都彰显出 JVM 在加强函数式编程方面做出的努力。

此文章为11月Day14学习笔记,内容来源于极客时间《云时代的 JVM 原理与实战》,强烈推荐该课程