
前言
为什么写作本书
Java语言可谓程序语言界的常青藤,自1996年诞生以来,长期在最受欢迎的编程语言排行榜中占据领先地位。除了语言本身的优秀特性之外,Java语言持续演进、不断发展也是它能够保持长盛不衰的重要原因。
近年来,随着云原生浪潮的兴起,越来越多的应用被部署在了云厂商的云服务环境中,以计算资源的形式为用户提供服务。在这种趋势下,应用本身越来越小,对跨平台的需求越来越弱(因为平台问题已经由云厂商解决了),但是对应用快速启动、即起即用和高性能执行的需求越来越强。Java程序的冷启动问题在这种场景下就显得格外突出,成为开发人员在选择编程语言时的主要减分项。根据著名的TIOBE编程语言流行趋势索引统计,Java语言的市场占有率从2016年1月的21.4%跌至2021年8月的10%[1],在C和Python之后,排名第三。
难道使用Java语言就只能忍受冷启动问题吗?Java社区和工业界一直在探索冷启动问题的解决之道,希望使用Java的用户在享受Java丰富生态的同时,还能获得良好的启动性能。比如OpenJDK提出的AppCDS(Application Class Data Sharing)技术,可以将已经加载的类的元数据导出到文件,在下次启动时直接从文件导入这些数据,无须再次经过类的解析和加载等过程,由此削减启动时的类加载开销。但是,因为Java的冷启动问题的根源在于JVM本身,所以在JVM之上做的各种优化的效果都是有限的,难以实现质的飞跃。
从根本上审视Java冷启动问题可以发现,启动一个Java程序并让它达到性能的峰值需要经过VM初始化→应用程序初始化→字节码解释执行→JIT编译热点函数→执行JIT编译后的本地代码(native code)等环节,且不论在这些环节上能够做出何种优化,单这么长的一条链路已足以说明冷启动问题之复杂、难解。如果不能打破这条链路,而只是在各个环节上进行优化,恐怕很难达到理想的效果。那么是否能够打破这条长链,越过中间环节直达最后一步,像C语言一样直接将Java代码编译为本地代码执行呢?
答案是肯定的,这就是本书要为读者展现的Java静态编译技术。Oracle公司推出的开源高性能多语言运行平台项目GraalVM,打造了一个包括静态编译器和轻量级运行时的Java静态编译框架,可以将Java程序从字节码直接编译为本地可执行应用程序。与在JVM下执行相比,静态编译后的Java程序的启动速度最高能够提升两个数量级,完全解决了冷启动问题,实现了Java应用程序启动性能的质的突破。目前关于GraalVM静态编译的大多数资料都是开发团队发布的技术文档、博客和GitHub上的开发相关问题讨论,而缺少系统全面性的资料介绍,尤其缺乏中文资料。因此国内的广大程序开发者和技术爱好者对其并不了解。本书旨在填补这方面的空白,使读者能够系统性了解并掌握GraalVM静态编译技术。
本书特色
本书将为读者详细解释GraalVM中的Java静态编译技术,不仅带你了解GraalVM的静态编译框架的使用方法,更重要的是向你介绍其背后的实现原理。有兴趣的读者在阅读完本书后可以独立阅读甚至修改GraalVM中的源码,并向社区提出自己的功能改进建议或Bug修复的补丁,帮助GraalVM更好地发展。本书侧重介绍GraalVM静态编译框架和运行时的应用与原理,而不太涉及编译部分。原因如下:其一,GraalVM的静态编译中使用的编译器并不专用于Java静态编译,如可用于代替HotSpot的C2编译器,其内容博大精深,足以单独成书,所以不会过多阐述;其二,Java静态编译的难点并不在于编译本身,而是在于确定编译的范围以及对JVM原本动态运行时的改造适配等,因为JVM的实时编译器早已实现对Java字节码的编译。
如何阅读本书
本书分为三部分,分别从应用、实现原理和具体实例三个方面进行阐述。
第一部分(第1~4章)从整体上介绍GraalVM项目及其静态编译子项目Substrate VM[2]。
第1章向读者介绍Java静态编译产生的技术原因——Java冷启动问题的产生和由来。
第2章首先对GraalVM做概要介绍,然后分别介绍Substrate VM和方舟编译器这两种实现方案,并对比它们的技术特点。
第3章向读者介绍Oracle GraalVM项目的整体结构。
第4章介绍使用GraalVM静态编译Java应用的详细步骤。
第二部分(第5~12章)主要介绍GraalVM中静态编译框架子项目Substrate VM的实现原理。
第5章介绍Substrate VM静态编译框架的实现与总体流程。
第6章介绍Substrate VM中的功能扩展机制——Feature机制,框架中的各个具体功能点都是通过该机制实现的。
第7章介绍编译时的程序元素替换功能——Substitution机制,该机制实现了无侵入性的程序元素替换能力,在静态编译框架的运行时实现中有基础性的地位。
第8章介绍Substrate VM的类提前初始化优化技术,该技术将符合条件的类在编译时初始化,不但节省了运行时初始化的开销,而且无须分析已经运行过的类初始化函数,因此降低了编译时的静态分析开销。
第9章和第10章分别介绍两种具有代表性的Java动态特性——反射和序列化的静态化实现过程。
第11章和第12章介绍Substrate VM的跨语言编程能力。
第三部分(第13~15章)通过两个实例介绍Java静态编译技术的实践,并在最后介绍程序在静态编译后的产物native image的调试方法。
第13章介绍云原生应用的静态编译和部署实例,侧重云服务平台的部署和性能比较。
第14章介绍用Java实现JVMTI Agent的实例,侧重Substrate VM框架对JVMTI编程的支持。
第15章介绍对native image的调试支持,静态编译后的Java程序已经是本地程序,不再支持原先的Java调试方式,而只能通过GDB调试。本章介绍如何用GDB调试native image程序。
勘误与支持
因为时间仓促,加上笔者水平有限,书中难免有错误之处,敬请读者不吝赐教。如果你有更多的宝贵意见,欢迎发送邮件至lin.ziyi@hotmail.com,期待能得到你的真挚反馈。
致谢
本书献给我的母亲朱桂智,没有她的辛勤养育就没有我的今天。还要感谢我的家人、老师和同事们的鼓励、鞭策和支持。
[1]参见https://www.tiobe.com/tiobe-index/java/。
[2]Oracle和华为两家公司走在开发、实现Java静态编译技术的前列,它们各自推出了自己的Java静态编译技术方案——GraalVM的Substrate VM和方舟编译器。本书的主角就是Substrate VM。