JVM工作原理与实战(三十六):GraalVM虚拟机

前言

JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了GraalVM、GraalVM的两种运行模式、GraalVM应用场景、参数优化和故障诊断等内容。


一、GraalVM介绍

GraalVM是由Oracle官方推出的一款高性能Java开发工具包(JDK),与OpenJDK和Oracle JDK相比,它为用户提供了更出色的性能。GraalVM标语为"Build faster, smaller, leaner applications"(更快、更小、更精简的应用程序开发)。GraalVM具有以下特点:

  • 低CPU和内存使用率: 与传统的JDK相比,GraalVM在执行应用程序时可以显著降低CPU和内存的使用率,从而提高应用程序的性能。

​

  • 快速启动和预热: GraalVM能够实现快速的应用程序启动,并且无需预热即可获得最佳性能,从而缩短了应用程序的启动时间。

​

  • 更好的安全性: GraalVM提供了更高级别的安全性,可以更好地保护应用程序免受攻击和数据泄露等安全威胁。
  • 小型可执行文件: 通过优化和压缩技术,GraalVM可以生成更小的可执行文件,从而减少了应用程序的存储空间占用。
  • 支持多种框架: GraalVM支持多种流行的Java框架,如Spring Boot、Micronaut、Helidon和Quarkus,使得开发人员可以更加方便地构建和部署应用程序。
  • 云平台支持: GraalVM已经得到了多家云平台的支持,使得开发人员可以轻松地将应用程序部署到云环境中。
  • 多语言支持: 通过Truffle框架,GraalVM可以运行JavaScript、Python、Ruby等多种其他语言,从而扩展了其应用范围。

GraalVM的官方网址:

GraalVM

GraalVM分为社区版(Community Edition)和企业版(Enterprise Edition)。与社区版相比,企业版在性能方面进行了更多的优化和改进,提供了更高级别的功能和特性。建议在开发高性能、安全可靠的应用程序时使用企业版GraalVM。

特性 描述 社区版 企业版
收费 是否收费 免费 收费
G1垃圾回收器 使用G1垃圾回收器优化垃圾回收性能 × √
Profile Guided Optimization(PGO) 运行过程中收集动态数据,进一步优化本地镜像的性能 × √
高级优化特性 更多优化技术,降低内存和垃圾回收的开销 × √
高级优化参数 更多的高级优化参数可以设置 × √

二、GraalVM的两种运行模式

JIT(Just-In-Time)模式(即时编译模式) :

JIT模式是GraalVM的一种核心特性,其处理方式与Oracle JDK的JIT编译器类似。在这种模式下,GraalVM的即时编译器将Java字节码转换为本地机器码,以实现更高的执行效率。其主要特点如下:

  • 一次编写,到处运行(Write Once, Run Anywhere) :这是Java的核心承诺,意味着开发者可以使用GraalVM在任何支持Java的平台或环境中编译和运行他们的代码。
  • 热点代码优化:预热之后,GraalVM的即时编译器会针对频繁执行的代码段进行优化,生成比传统的Hotspot JIT更高的性能机器码。

​

AOT(Ahead-Of-Time)模式(提前编译模式) :

AOT模式是GraalVM的另一项创新,它允许开发人员在编译阶段就生成特定平台的可执行文件。这意味着应用程序在启动时已经预先编译为本地代码,从而实现了更高的启动速度和运行性能。其主要特点如下:

  • 本地可执行文件生成:通过AOT编译器,开发人员可以为特定平台(如Windows、Linux或macOS)生成可执行文件(如.exe、.app或.out)。
  • 启动后达到最高性能:由于应用程序在启动时已经转换为本地代码,因此无需进行额外的编译或优化,可以立即达到最佳性能。
  • 非跨平台编译:与JIT模式不同,AOT模式下生成的可执行文件不具备跨平台特性。每个目标平台都需要单独编译。
  • 本地镜像(Native Image) :AOT模式下生成的文件被称为本地镜像,它们是为特定平台和配置预先编译的应用程序映像。

​

在选择使用GraalVM的哪种模式时,开发人员应考虑他们的应用程序需求、目标平台以及对性能、跨平台兼容性和安全性的要求。JIT模式提供了高度的跨平台兼容性和动态优化能力,而AOT模式则专注于预先编译的高性能和特定平台的可执行文件。

GraalVM模式和版本的性能对比:

​

三、GraalVM应用场景

1.GraalVM存在的问题

GraalVM的AOT模式虽然带来了启动速度、内存和CPU开销上的优势,但也存在一些问题需要解决:

  • 跨平台问题:由于AOT模式下的代码是针对特定平台编译的,因此在使用不同平台运行时需要进行多次编译。这增加了开发人员的工作量,并需要确保编译平台的依赖库等环境与运行平台保持一致。
  • 编译时间与资源消耗:使用AOT模式编译本地镜像时,需要较长时间,并且会消耗大量的CPU和内存资源。这可能对开发环境和持续集成/持续部署(CI/CD)流程造成影响。
  • 运行时类访问限制:AOT编译器在编译时需要知道运行时所有可访问的类。然而,Java中存在一些技术可以在运行时动态创建类,例如反射、动态代理等。这些技术在许多框架中广泛使用,如Spring框架。因此,这些框架需要与AOT编译器进行适配,以确保其功能的正常使用。

针对上述问题,以下是一些可能的解决方案:

  • 使用容器化平台:利用公有云的Docker等容器化平台进行在线编译,可以确保编译环境和运行环境的一致性。这样不仅解决了跨平台问题,还解决了编译资源问题。通过容器化技术,可以轻松地在不同的环境中构建和部署应用程序。
  • 采用整合了GraalVM AOT模式的框架版本:例如,使用Spring Boot 3等框架版本,这些框架已经与GraalVM AOT模式进行了深度整合,简化了适配过程,并可能提供了更好的性能和功能支持。

2.GraalVM企业级应用-Serverless架构

在传统的系统架构中,企业需要自行负责服务器等基础设施的运维、安全和高可用性等方面的工作,这带来了两个主要问题:

  • 开销巨大:这包括了人力成本的开销和机房建设的开销。企业需要配备专门的技术团队进行基础设施的管理和维护,同时还需要投入大量的资源进行机房建设和设备采购。
  • 资源浪费:面对流量冲击,例如秒杀等促销活动,企业必须提前规划并准备大量的服务器资源。然而,在活动结束后,这些服务器可能会处于闲置状态,导致资源的严重浪费。

为了解决这些问题,随着虚拟化技术和云原生技术的不断成熟,云服务商开始提供Serverless无服务器化的架构。这种架构使得企业无需进行服务器的任何配置和部署,完全由云服务商负责提供和管理基础设施。Serverless架构能够根据应用程序的实际需求动态地分配资源,确保应用程序的高可用性和弹性扩展。

在Serverless架构中,企业可以将应用程序部署到云服务商提供的平台上,并利用云服务商提供的API和事件驱动的机制来编写业务逻辑。这样,企业可以专注于应用程序的开发和业务逻辑的实现,而无需关心基础设施的管理和维护。比较典型的Serverless服务提供商包括亚马逊AWS和阿里云等。这些云服务商提供了丰富的Serverless服务,如函数计算、数据库、存储和消息队列等,使得企业可以更加便捷地构建和部署Serverless应用程序。通过采用Serverless架构,企业可以降低开销、减少资源浪费,并实现应用程序的高可用性和弹性扩展。同时,与GraalVM的结合使用可以进一步提高应用程序的性能和安全性,为企业提供更加高效和可靠的解决方案。

3.Serverless架构-函数计算

在Serverless架构中,函数计算是一种常见的服务模式,它将应用程序拆分为多个独立的函数,每个函数都以事件驱动的方式运行。这种模式的核心思想是将应用程序的逻辑分解为一系列独立的、可复用的函数,从而提高了应用程序的可维护性和可扩展性。函数计算的服务提供商包括亚马逊AWS的Lambda和阿里云的FC等。这些服务提供商提供了全面的函数计算解决方案,使开发人员能够专注于编写和部署函数逻辑,而无需关心底层基础设施的管理和维护。

函数计算的主要应用场景包括:

  • 小程序和API服务中的接口:对于调用频率较低的接口,使用常规的服务器架构可能会导致资源浪费。通过使用Serverless架构,开发人员可以实现按需付费,降低成本,同时利用自动伸缩功能应对流量的突发情况。
  • 大规模任务处理:对于需要处理大量数据或执行复杂计算的任务,例如音视频文件转码、审核等,可以利用事件机制在文件上传后自动触发相应的任务。函数计算可以提供高效的资源利用和弹性扩展能力,以满足大规模任务处理的需求。

在计费方面,函数计算通常基于CPU和内存使用量进行计费。因此,使用GraalVM AOT模式编译本地镜像可以进一步降低成本。通过使用GraalVM AOT编译器,开发人员可以生成高效的本地镜像,从而减少运行函数所需的CPU和内存资源,进而降低函数计算的计费成本。

4.Serverless架构-Serverless应用

在Serverless架构中,除了函数计算服务外,云服务商还提供了基于容器的Serverless应用作为另一种解决方案。这种方案针对函数计算服务的局限性,为需要更长时间运行或更大资源需求的应用程序提供了支持。

基于容器的Serverless应用的核心优势在于其自动化的容器管理。与传统的手动配置Kubernetes中的Pod和Service等内容不同,基于容器的Serverless应用简化了这一过程。开发人员只需选择所需的镜像,云服务商即可自动生成应用服务,无需进行繁琐的配置和管理。这种方案适用于各种应用场景,特别是需要长时间运行或大量资源支持的应用。例如,一些批处理任务、大数据处理和分析、实时流数据处理等场景,都可以通过基于容器的Serverless应用实现高效的处理和扩展。

在计费方面,基于容器的Serverless应用通常也基于CPU和内存使用量进行计费。因此,使用GraalVM AOT模式编译本地镜像可以进一步降低成本。通过使用GraalVM AOT编译器,开发人员可以生成高效的本地镜像,从而减少运行应用所需的CPU和内存资源,进而降低基于容器的Serverless应用的计费成本。

四、参数优化和故障诊断

在GraalVM中,由于它是一款独立的JDK,许多在HotSpot虚拟机中常用的参数在这里并不适用。为了确保最佳的性能和稳定性,需要对GraalVM的参数进行细致的调整和优化。以下是一些关键的参数和故障诊断建议:

内存管理参数:

  • 最大堆大小(Max Heap Size) : 社区版GraalVM默认使用串行垃圾回收器(Serial GC),其最大Java堆大小默认设置为物理内存的80%。如需调整,可以使用-Xmx参数来设置最大堆大小。如果希望在编译期就指定该大小,可以在编译时添加-R:MaxHeapSize=最大堆大小参数。
  • G1垃圾回收器 : 企业版GraalVM提供了G1垃圾回收器,它能有效降低垃圾回收的延迟。开启方式为添加--gc=G1参数。
  • Epsilon GC : 对于生命周期短暂且不产生大量对象的程序,可以考虑使用Epsilon GC。它不会产生任何垃圾回收行为,从而没有额外的内存和CPU开销。开启方式为添加--gc=epsilon参数。

垃圾回收日志与诊断:

  • 使用-XX:+PrintGC和-XX:+VerboseGC参数可以打印出垃圾回收的详细信息,这对于故障诊断和性能调优非常有帮助。

性能优化时可以指定的一小部分选项:

ruby 复制代码
-H:G1HeapRegionSize(只能在映像构建时指定) - G1 区域的大小。
-XX:MaxRAMPercentage- 如果未另行指定最大堆大小,则用作最大堆大小的物理内存大小的百分比。
-XX:MaxGCPauseMillis- 最长暂停时间的目标。
-XX:ParallelGCThreads- 在垃圾回收暂停期间用于并行工作的最大线程数。
-XX:ConcGCThreads- 用于并发工作的最大线程数。
-XX:InitiatingHeapOccupancyPercent- 触发标记周期的 Java 堆占用阈值。
-XX:G1HeapWastePercent- 候选集合集中允许的未回收空间。如果候选收集组中的可用空间低于该值,则 G1 将停止空间回收阶段。

其他常用的参数参考:

Memory Management (graalvm.org)


总结

JVM是Java程序的运行环境,负责字节码解释、内存管理、安全保障、多线程支持、性能监控和跨平台运行。本文主要介绍了GraalVM、GraalVM的两种运行模式、GraalVM应用场景、参数优化和故障诊断等内容,希望对大家有所帮助。

相关推荐
瑞码空间20 分钟前
面向接口编程与开闭原则在模拟 JDBC 驱动中的应用
java·jdbc
zhoujungis31 分钟前
登录态 1 小时就掉?Django + Vue 双 Token 认证实战 | 尘世栈帧
后端
Félix25137 分钟前
Nacos学习笔记(SpringBoot/SpringCloud)
java·spring boot·spring
文丑颜不良啊42 分钟前
LeetCode1581~1600题目解析
java·leetcode
香蕉大香蕉(06敬畏市场)42 分钟前
MySQL 单点详解(06)
java·数据库·mysql·博客·实习
武子康1 小时前
同一台 ESP32,GSM 能消回声,VoIP 为什么不行?
人工智能·后端·agent
用户69371750013841 小时前
AI 能写代码,但工程架构还是应该由人来定
前端·后端
lqbzlll1 小时前
Spring Boot 开启虚拟线程后接口反而变慢了?4 个排查方向和对应修法
java·spring boot·后端
七夜zippoe1 小时前
LangChain4j vs Spring AI:Java AI 框架怎么选(对比表)
java·人工智能·spring·ai·langchain4j
悠仁さん1 小时前
【C++】set map 使用
java·前端·c++