OpenJDK8 编译,调试和目录结构

目录

一、下载源码

二、编译

三、搭建开发环境

四、GDB调试

五、目录结构说明


一、下载源码

    可选择在OpenJDK(http://hg.openjdk.java.net/jdk8u)的官方代码仓库下载zip包,如下图所示:

OpenJDK8 编译,调试和目录结构_第1张图片

    可选择命令行的方式,先执行sudo yum install Mercurial 安装类似git的仓库管理工具hg,然后执行hg clone http://hg.openjdk.java.net/jdk8u/jdk8u命令下载源代码中最外层的目录,最后执行sudo sh get_source.sh下载所有子目录如上图jdk,hotspot下的代码。

     这两种方式都是直接访问位于国外的官网,没有国内镜像,网速相当不稳定,容易下载失败。笔者后面在Githup上搜到一个由AdoptOpenJDK社区维护的镜像仓库(https://github.com/AdoptOpenJDK/openjdk-jdk8u),果断fork到自己的Github账号下,从Github上下载源码就快很多了,如下图:

OpenJDK8 编译,调试和目录结构_第2张图片

      AdoptOpenJDK提供了一个一键构建工具openjdk-buildhttps://github.com/AdoptOpenJDK/openjdk-build),官网的介绍是执行一条命令./makejdk-any-platform.sh jdk8u 即可完成编译,笔者因为公司网络管制无法在Linux虚机上访问Github,有兴趣的同学可尝试。

     参考:OpenJDK8源码编译(Ubuntu 16.04)

                openJDK之如何下载各个版本的openJDK源码

二、编译

     在windows上编译强依赖微软的Visual Studio的C/C++编译器,执行./configue时会根据当前操作系统类型强校验编译器类型,支持的编译器如下图:

OpenJDK8 编译,调试和目录结构_第3张图片

本身没有安装Visual Studio的都推荐在Linux上编译。具体步骤如下:

1、确保已安装1.7的JDK,OpenJDK源码中Java API相关的Java代码需要借助已安装的JDK编译。OpenJDK7需要通过Ant脚本构建,还需要安装Ant相关依赖并配置环境变量,OpenJDK8改成经典的C编译方式,更加方便快捷。

2、sudo unzip openjdk-jdk8u-master.zip,将源码zip包解压

3、sudo sh ./configure --with-target-bits=64 --with-boot-jdk=/export/servers/jdk1.7.0_71 --with-debug-level=slowdebug --disable-zip-debug-info,执行配置依赖检查,生成Makefile,各参数含义如下:

  • –with-target-bits=64 :指定生成64位jdk;
  • –with-boot-jdk=/usr/java/jdk1.7.0_80/:启动jdk的路径;
  • –with-debug-level=slowdebug:编译时debug的级别,有release, fastdebug, slowdebug 三种级别;
  • –disable-zip-debug-info:禁止压缩生成的调试符号信息,方便gdb调试获取当前正在执行的源代码和行号等调试信息;

其他选项和构建相关环境变量配置参考sudo sh ./configure --help的说明。检查完成会提示缺少的依赖包,大部分情况按照提示通过yum命令安装即可,如下图:

 笔者反复执行上述安装命令一直报错,最后Google发现configue执行过程会记录日志config.log,查看具体的报错信息发现并不是缺少Xrender.h而是在加载XTest.h过程中发现XInput.h不存在,如下图:

OpenJDK8 编译,调试和目录结构_第4张图片

进一步Google该头文件属于 libXi-devel包,执行sudo yum install libXi-devel后再configue,检查通过,如下图:

OpenJDK8 编译,调试和目录结构_第5张图片

4、sudo make all执行编译,这个过程快慢依赖机器的硬件了,笔者大概花了10分钟左右, 下面是二次编译完成的截图:

OpenJDK8 编译,调试和目录结构_第6张图片

5、编译完成,会在根目录下生成build文件夹,保存构建的结果和相关脚本,进入保存java启动入口二进制文件的jdk/bin目录下,执行./java -version,正常输出则编译成功,如下图:

OpenJDK8 编译,调试和目录结构_第7张图片

       参考:linux编译openjdk8

                 JAVA虚拟机学习笔记(一)Windows10下编译OpenJDK8 

                 make 和 make install 的区别

三、搭建开发环境

     因为C/C++本身不是严格的跨平台语言,所以最好保证开发环境跟编译环境一致,推荐使用Ubuntu桌面版Linux + Eclipse。不要使用Netbeans,不要使用Netbeans,不要使用Netbeans!!!刚开始笔者参考部分博客的引导使用Netbeans,Netbeans 8以上的新版本不支持C/C++,装上Netbeans 8 C/C++版查看OpenJDK源码就发现一堆莫名其妙的引用报错,找不到头文件,无法解析某个方法或者变量等,让人非常头大,最后放弃选择同样轻量级的IDE Eclipse。Eclipse C/C++开发通Java完全不同,也是不停磕磕碰碰。

     那么常见的不带桌面系统的CentOS可以安装Eclipse么?笔者尝试过,不行,因为Eclipse的UI界面强依赖操作系统本身的桌面系统支持,CentOS可以安装GNOME或者KDE等桌面系统,或者安装X Window System,借助其他已安装桌面系统的CentOS来显示界面也可以,总之就是得伤筋动骨。

    因为公司办公环境通常都是Windows,有没有办法在Windows上模拟Linux环境了?最简单粗暴的,在Window上借助Oracle VM VirtualBox安装一个虚拟机,在虚拟机内安装Ubuntu,前提是办公电脑配置高。还有一种比较省事的,远程开发,即代码开发在Windows上,IDE 通过sftp等方式将变动的代码同步远程Linux虚机上,利用远程Linux虚机的gcc/g++编译器编译调试代码,前提是能够直连这台Linux虚机并且有足够的权限,如今堡垒机盛行,这条路基本堵死了。最通用的解决办法是Cygwin或者MinGW,两者都是利用Windows本身的库函数来实现Linux上通用的GNU工具集合,如gcc编译器。MinGW是一种傻瓜式的按最低的标准配置安装,一键安装完成,安装包较小,但是缺乏灵活性,无法便捷安装其他依赖包。Cygwin在使用上相当于yum命令,提供上千种依赖供选择,并自动下载安装相关的依赖包,非常灵活,下面详细说明安装步骤:

1、到Cygwin官网(https://cygwin.com/install.html)下载最新的安装包,setup-x86_64.exe

2、点击执行,按照默认选项一直点下一步直到下图:

OpenJDK8 编译,调试和目录结构_第8张图片

一开始会尝试从官网下载依赖,自然尝试失败,这儿是让我们输入国内可用的镜像地址,输入阿里云的镜像地址 http://mirrors.aliyun.com/cygwin/,注意空格,点击Add-->下一步,安装包检验镜像地址是否可用然后拉取必要的目录信息,然后进入下下图:

OpenJDK8 编译,调试和目录结构_第9张图片

这是可供选择的各种依赖的列表,鼠标放到Full上可以查看各种View的含义:

OpenJDK8 编译,调试和目录结构_第10张图片

这里我们直接输入gcc,g++,make,gdb,其中gcc是C的编译器,g++是C++的编译器,make是从源代码构建可执行文件的工具,gdb是调试工具,然后search即可, 如下图:

OpenJDK8 编译,调试和目录结构_第11张图片

OpenJDK8 编译,调试和目录结构_第12张图片

OpenJDK8 编译,调试和目录结构_第13张图片

   图中的带debuginfo后缀的依赖都是各个依赖本身编译时产生的调试信息,也可不安装。接着点下一步,如下图:

OpenJDK8 编译,调试和目录结构_第14张图片

这是即将安装的依赖列表,第一次安装时,Cygwin会安装很多基础的依赖包如cd命令,ls命令等,第二次安装就只有你选择的依赖及其依赖的其他组件。继续点击下一步, 就会自动下载并安装了:

OpenJDK8 编译,调试和目录结构_第15张图片

 安装结束,点击桌面的Cygwin图标会弹出一个命令行界面,在此界面可以执行常用的Linux命令,如果提示不存在则可以重新执行上述步骤安装对应的依赖即可,如unzip。输入gcc --version,如果正确显示则安装成功,如下图:

OpenJDK8 编译,调试和目录结构_第16张图片

 Cygwin中默认字体较小,可右键options-->Text改变字体,配置快捷键等,如下图:

OpenJDK8 编译,调试和目录结构_第17张图片

 Cygwin在安装目录下会初始化类似于Linux的目录结构,启动后我们进入的目录就是C:\cygwin64\home\Administrator下,取决于当前用户的账户了,如下图:

OpenJDK8 编译,调试和目录结构_第18张图片

至此Cygwin安装成功,下一步配置Eclipse,首先从官网下载支持C/C++版的Eclipse,如果是普通版则需要在Help-->Eclipse Marketplace中搜索cdt并安装了,如下图:

OpenJDK8 编译,调试和目录结构_第19张图片

 支持C/C++版的Eclipse默认安装该插件。

接着配置环境变量,将Cygwin的安装目录放到PATH中,方便Eclipse从PATH中自动识别gcc编译器,如下图:

OpenJDK8 编译,调试和目录结构_第20张图片

 配置完成就可以新建C/C++工程了,注意选择工程类型为C++ Managered Build,其他工程类型识别不了已安装的Cygwin,如下图:

OpenJDK8 编译,调试和目录结构_第21张图片

点击Next,逐一选择ToolChains为Cygwin GCC,然后finish即可,如下图:

OpenJDK8 编译,调试和目录结构_第22张图片

正常的项目会自动将Cygwin下include等包含头文件和依赖库的目录带出来,如果安装了第三方依赖库提示找不到对应头文件,则需要更改图中的include的配置了,如下图:

OpenJDK8 编译,调试和目录结构_第23张图片

按照Java的做法,这时右键,Run as-->Local C/C++ Application,报错:

OpenJDK8 编译,调试和目录结构_第24张图片

这个错误是因为Eclipse运行的时候没有在工程目录下找到二进制的可执行文件,很容易误以为是缺乏库文件一类的,解决办法是先执行Build,右键 Build Project即可,可在控制台看到构建执行的命令,在工程目录下看到生成的二级制可执行文件,如下图:

 OpenJDK8 编译,调试和目录结构_第25张图片

OpenJDK8 编译,调试和目录结构_第26张图片

这时再执行右键,Run As就会成功了,如下图:

OpenJDK8 编译,调试和目录结构_第27张图片

    实际代码开发中经常需要测试某个函数,有没有类似Java JUnit的快捷的方法了?答案是没有,有单元测试框架但是没有跟IDE很好集成。有一种替代方案,利用命令行编译并执行单个C/C++文件。首先把工程建立在Cygwin的用户目录下,方便快速找到测试文件,注意不使用默认路径时需要加上项目的根目录,如下图:

OpenJDK8 编译,调试和目录结构_第28张图片

接着创建src目录,创建新的source file文件,注意必须把文件后缀带上,因为存在.c,.h,.cpp,.hpp等多种后缀,IDE无法像创建Java文件一样自动加上.java后缀,如果不加则识别成普通的文本文件了,这时会给提示,如下图:

OpenJDK8 编译,调试和目录结构_第29张图片

文件创建完成后,就可以在Cygwin的控制台中找到对应的文件了, 执行命令g++ -g CppTest.cpp  -o CppTest生成二进制文件,注意生成的二进制文件是exe后缀的,因为windows操作系统只支持这种二进制文件,然后命令行运行该文件即可,如下图:

OpenJDK8 编译,调试和目录结构_第30张图片

至此,整个开发环境就搭建好了,下一步就是导入OpenJDK的源码了,导入方式跟Java工程一样,New-->Import-->Existing Code As Makefile Project,输入源代码路径,如下图: 

OpenJDK8 编译,调试和目录结构_第31张图片

导入完成Eclipse会自动解析源代码中的各种引用和调用关系,自动配置必要的环境变量,然后就可以愉快的看代码了,如下图:

OpenJDK8 编译,调试和目录结构_第32张图片

Eclipse比Netbeans强大的是不仅能解析正常的方法调用,也能准确找到同一个类在不同操作系统下的实现,可以帮助我们从整体上了解JVM的实现,如下图:

OpenJDK8 编译,调试和目录结构_第33张图片

       参考: windows 安装cygwin教程

                   Linux在远程X Server上显示图形界面

                   安装CentOS桌面环境

                   深入理解debuginfo

                    C++单元测试入门指南-在eclipse上建立Google test

四、GDB调试

    GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,相比IDE中的调试工具,命令行的GDB更加强大,灵活,是Linux上调试内核驱动及C/C++应用程序的利器,GDB主要可帮助工程师完成下面4个方面的功能:

  • 启动程序,可以按照工程师自定义的要求随心所欲的运行程序。
  • 让被调试的程序在工程师指定的断点处停住,断点可以是条件表达式。
  • 当程序被停住时,可以检查此时程序中所发生的事,并追索上文。
  • 动态地改变程序的执行环境。

    GDB支持的命令行选项通过gdb  --help查看,输入gdb即启动gdb,默认会打印当前GDB的版本信息等,可以使用-q选项禁止输出,然后输入help选项,可以查看gdb提供各系列的调试命令,如breakpoints表示断点相关的命令,输入help breakpoints可以查看该系列下所有的命令,输入help break可以查看该命令的使用说明,如下图所示:

OpenJDK8 编译,调试和目录结构_第34张图片

OpenJDK8 编译,调试和目录结构_第35张图片

OpenJDK8 编译,调试和目录结构_第36张图片

注意使用gdb命令调试前,需要保证gcc或者g++编译时加了-g选项,该选项用于生成调试信息,方便gdb获取当前执行的代码,行号,变量名等信息。下面演示下OpenJDK的调试步骤:

1、OpenJDK编译完成会在根目录下生成一个build目录,进入该目录即是编译的结果,如下图:

 2、java的启动入口,即名为java的二进制文件在jdk/bin目录下,进入该目录,执行gdb -q ./java,表示调试java这个二进制文件,注意此时程序并未运行。如下图:

OpenJDK8 编译,调试和目录结构_第37张图片

2、执行set args -version设置启动参数,执行set env _JAVA_LAUNCHER_DEBUG= 1设置环境变量,_JAVA_LAUNCHER_DEBUG为1表示会打印启动过程中的关键参数。

3、在不知道启动入口文件的前提下可以执行start命令,gdb会自动停留在启动入口main函数,然后可以查看该函数的文件信息,如果已经知道启动入口并设置了断点,则可以执行run命令,gdb会停到设置的第一个断点处。注意此时需要执行n命令表示进入到main.c这个文件的调试中,否则后面设置断点会无法准确定位到main.c这个文件,如下图:

OpenJDK8 编译,调试和目录结构_第38张图片

4、找到启动入口了,接着在IDE中查看具体的代码,顺着代码的调用路径找到自己想要断点调试的地方,如下图:

OpenJDK8 编译,调试和目录结构_第39张图片

导入工程后这个地方一直报错 Symbol 'FULL_VERSION' could not be resolved,是我们下载的代码有问题么?肯定不是代码问题,那这两个宏是哪来的了?答案在main.c引入的头文件defines.h中,如下图:

OpenJDK8 编译,调试和目录结构_第40张图片

IDE的预处理器都走到#error这一步,说明当前整个工程代码都没有定义FULL_VERSION,JDK_MAJOR_VERSION,JDK_MINOR_VERSION这三个宏,但是我们编译成功,说明编译时肯定是有这三个宏的,那这三个宏的定义究竟在哪?全局搜索FULL_VERSION,结果只有这个defines.h有,如下图:

OpenJDK8 编译,调试和目录结构_第41张图片

在源代码上已经找不到答案了,那就调试呗,看看实际穿进去的是啥值,通过b 125命令在这行代码处设置断点。

5、 执行c命令,即继续运行程序直到下一个断点处,此时我们还是看不到调用JLI_Launch具体的参数,可以执行s命令,表示调试这个函数的执行,此时调用参数就都打出来了,如下图:

OpenJDK8 编译,调试和目录结构_第42张图片

从上述取值分析,这两个宏并不是源代码中写死的,而是在编译前的预处理环节由构建脚本根据构建配置动态生成的,具体的脚本位置还在探索中。

6、继续查看JLI_Launch函数的实现,我们想看InitLauncher函数的实现,然后Eclipse告诉我们有两种实现,分别是solaris和windows的,为啥没有Linux的呢?进一步查看与solaris同级的Linux目录下只有一个doc文件夹,难道是Linux的实现跟某个平台一样?如下图:

OpenJDK8 编译,调试和目录结构_第43张图片

OpenJDK8 编译,调试和目录结构_第44张图片

为了确定InitLauncher函数的实现,我们得debug该函数,gdb会告诉我们答案,执行n表示进入JLI_Launch所处的代码文件调试,执行b 207 打断点,执行c继续执行至该断点处,执行s进入该函数,答案是solaris下的试下,如下图:

OpenJDK8 编译,调试和目录结构_第45张图片

为啥Linux可以使用跟solaris一样的实现了?答案是两者都是Unix的衍生版本,底层的库函数基本一致。

7、我们进入了InitLauncher函数的调试了,如果不想跳出该函数的调试怎么办?执行finish即可,然后gdb会进入到InitLauncher的下一个函数DumpState处,如下图:

8、至此gdb调试常用的命令介绍完了,执行c继续运行,居然报错了,如下图:

OpenJDK8 编译,调试和目录结构_第46张图片

Program received signal SIGSEGV, Segmentation fault 表示可能应用程序访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址,难道这是gdb的bug??

9、观察报错输出的下一行Switching to Thread,切换到进程257947了,这行输出是啥意思?查看源码,JLI_Launch--》JVMInit--》ContinueInNewThread--》ContinueInNewThread0,参考注释,主要逻辑是创建一个新的线程,在新线程中创建JVM并调用main方法,具体执行的逻辑就是JavaMain了,如下图:

OpenJDK8 编译,调试和目录结构_第47张图片

 10、从源码得知,我们碰到多线程调试问题了,gdb是否支持多线程调试了?答案是肯定的,不过默认情况下只调试主进程,子进程会阻塞在创建进程的地方,可以执行info threads查看当前的进程信息,如下图:

标*号的进程为gdb当前调试中的进程,主进程是1,目前阻塞在pthread_join这个方法上,这个方法表示主进程休眠,直到子进程执行完任务并退出。

11、既然gdb已经切换到子进程了,那能不能继续调试子进程了?执行n,报错Cannot find bounds of current function,然后执行c,出现了正常java -version的输出:

OpenJDK8 编译,调试和目录结构_第48张图片

 从上图可知,实际创建了多个子进程,其中的一个子进程执行了版本信息打印,其他进程干啥了?啥时候产生的了?查看源码答案在JavaMain--》InitializeJVM--》CreateJavaVM中,参考注释,这是一个JNI调用了,不好直接调试了

OpenJDK8 编译,调试和目录结构_第49张图片

 打印java版本信息的方法在下面的PrintJavaVersion中,如下图:

OpenJDK8 编译,调试和目录结构_第50张图片

 printVersion这个属性在解析命令行参数的时候设置的,逻辑在JLI_Launch--》ParseArguments方法中,如下图:

OpenJDK8 编译,调试和目录结构_第51张图片

PrintJavaVersion的实现也是调用这个类的sun/misc/Version的println方法实现的,同样是借助JNI,如下图:

OpenJDK8 编译,调试和目录结构_第52张图片

之所以通过java类是实现而不是借助C代码,主要是利用java代码跨平台的特点,避免为不同的平台各自提供实现。

12、JNI调用的实现比较复杂,这里不做探讨,考虑下这个 sun/misc/Version类在哪呢?在项目根目录下执行find ./ -name Version.java命令,结果如下:

OpenJDK8 编译,调试和目录结构_第53张图片

按照包名去匹配,总共有四个符合条件的,分别是gensrc,gen_profile_1,gen_profile_2,gen_profile_3下的,这四个都是在build目录下,也就是构建时生成的,通过less命令查看源代码,代码内容也是基本一致的,初步判断gen_profile_1,gen_profile_2,gen_profile_3这个应该是跟构建过程有关的,最终使用gensrc下的,而且在jdk的src下应该有生成Version.java的模板之类的,查找源码,jdk-->src-->share-->classes-->sun-->misc-->Version.java.template,答案如下:

OpenJDK8 编译,调试和目录结构_第54张图片

13、OpenJDK的构建过程这里不做讨论,回到gdb调试,有没有办法调试PrintJavaVersion这段逻辑呢?执行b java.c:PrintJavaVersion 命令设置断点,然后执行run,中间一样报错Program received signal SIGSEGV,执行c继续往下运行,然后gdb就会停在PrintJavaVersion这了,如下图:

OpenJDK8 编译,调试和目录结构_第55张图片

其他gdb命令的使用可以参考官方文档和如下链接:

         Linux环境下段错误的产生原因及调试方法小结

          Linux gdb调试器用法全面解析

          使用gdb调试程序完全教程

          GDB 调试多进程或者多线程应用

          修改,编译,GDB调试openjdk8源码(docker环境下)

五、目录结构说明

 1、corba

       CORBA 全称是Common Object Request Broker Architecture,CORBA 1.1 由对象管理组织在 1991 年发布,他定义了接口定义语言(IDL)和应用编程接口(API),从而通过实现对象请求代理(ORB)来激活客户/服务器的交互。CORBA 2.0 于 1994 年的 12 月发布,他定义了如何跨越不同的 ORB 提供者而进行通讯。在功能上基本等同于Webservice,即:

  1. 实现了分布式系统下跨平台,跨语言的数据的传输
  2. 实现了远程方法的本地调用(在本地调用远程Server上的方法并取得返回值)

corba目录下为Java对该交互协议的实现,主要是Java代码。

      参考:使用Java/CORBA实现分布应用编程

                 WebService学习总结(一)——WebService的相关概念

2、jaxp

     JAXP的全称是Java API for XML Processing,是Java定义的一组操作XML文档的API,注意JAXP只是定义了API,并没有提供具体的实现,Java为了保证JAXP能够即装即用,默认带了Apache Xerces 解析器,代码位于jaxp/src/com/sun/org/apache下。 JAXP支持三种XML解析模型:

  1. DOM模型,位于jaxp\src\org\w3c\dom下
  2. SAX模型, 位于jaxp\src\org\xml\sax下
  3. STAX模型,位于jaxp\src\javax\xml\stream下,除stream目录外都是JAXP本身的API

     参考:JAXP 全面介绍,第 1 部分

                Java xml解析器SAX解析与StAX解析比较

               学习笔记——JAXP

3、jaxws

     JAX-WS全称是JavaTM API forXML-Based Web Services, 是一组基于SOAP协议实现的Web Service的API,与之相对的是JAX-RS,全称是JavaTM API for RESTful Webservices,是一组基于RESTful风格的Http服务实现Web Service的API。JAX-WS相关代码位于jaxws/src/share/jaxws_classes,其中com目录下主要是JDK内部实现使用的类,对外暴露的API都在javax目录下,org目录是JDK内部依赖的relaxng包,relaxng同W3C XML Schema ,DTD一样都是定义XML文档规范的一种语言。

    JAF全称是JavaBeans Activation Framework, JAF的目的在于统一处理不同数据格式的方法(不管数据格式为简单文本还是由图片、声音、视频甚至其它"活动"内容共同组成的复合文档),使得Java对象与编码数据流之间的映射变得非常容易,可以参考JavaMail中JAF的应用。JAF的相关代码位于jaxws/src/share/jaf_classes下。

     参考:【webservice】Java JAX-WS和JAX-RS webservice

                 真正的轻量级WebService框架——使用JAX-WS(JWS)发布WebService

                  JAF框架及在JavaMail中的应用

4、langtools

     langtools包下都是Java语言的支持工具实现,具体如下:

  1.   src/share/classes/com/sum/javadoc:  生成API文档的接口定义,即The Doclet API
  2.   src/share/classes/com/sum/source:  解析源码的接口定义
  3.   src/share/classes/com/sum/tools/doclets和doclint: javadoc文档生成工具源码
  4.   src/share/classes/com/sum/tools/classfile: 共用的读取解决classfile的工具源码
  5.   src/share/classes/com/sum/tools/javac:  javac Java代码编译工具源码
  6.   src/share/classes/com/sum/tools/sjavac:  sjavac Java代码多线程和增量编译工具源码,8中为初版
  7.   src/share/classes/com/sum/tools/javah: javah JNI调用中用于生成native接口的头文件的工具源码
  8.   src/share/classes/com/sum/tools/javap:javap 查看源代码编译后字节码的工具源码
  9.   src/share/classes/com/sum/tools/jdeps:jdeps 查看Java包或者类依赖的工具源码
  10.   src/share/classes/javax/lang/model: 用于语言建模、语言处理任务和API等
  11.   src/share/classes/javax/annotation/process: 注解的处理框架 

5、nashorn

     JDK8 内嵌的Nashorn JavaScript 引擎,扩展了Java在JVM上运行动态JavaScript脚本的能力,但是因为ECMAScript规范发展较快,Nashorn相关代码很难维护,JDK11预计将移除相关代码。

    参考: JDK 8 新特性 | Nashorn 脚本引擎

6、jdk

    其中aix,bsd,linux,macosx,solaris,windows是各平台的特定实现,其中aix,bsd,linux,solaris都是类Unix系统,基本共用solaris的实现。share目录下是平台无关的实现,具体如下:

  • bin目录是JVM的启动入口
  • classes目录是JDK源码
  • native目录是JDK源码中native接口的实现源码,
  • back目录是JDWP(Java Debug Wire Protocol ) Java调试通信协议的实现
  • transport目录是建立JDWP握手连接相关的实现
  • instrument目录是javaagent工具即JVMTIAgent 的实现

    参考: java agent基础原理

                JVMTI 和 Agent 实现

                JDWP 协议及实现

7、hotspot

     hotspot是JVM即JRE Java运行时环境的实现,具体如下:

├─agent                            Serviceability Agent实现,提供HSDB JVM调试工具
├─make                           编译构建相关代码
├─src                              HotSpot VM的源代码
│  ├─cpu                            不同CPU架构下CPU相关代码(汇编器、模板解释器、ad文件、部分runtime函数在这里实现)
│  ├─os                              不同OS下系统调用相关代码
│  ├─os_cpu                        跟OS和CPU架构相关的系统调用相关的代码,如用户栈操作
│  └─share                          平台无关的共用代码
│      ├─tools                        工具
│      │  ├─hsdis                      反汇编插件,用于查看JIT即时编译器产生的汇编代码
│      │  ├─IdealGraphVisualizer       将server编译器的中间代码可视化的工具
│      │  ├─LogCompilation             将-XX:+LogCompilation输出的日志(hotspot.log)整理成更容易阅读的格式的工具
│      │  └─ProjectCreator             生成Visual Studio的project文件的工具
│      └─vm                           HotSpot VM的核心代码
│          ├─adlc                       平台描述文件(上面的cpu或os_cpu里的*.ad文件)的编译器
│          ├─asm                        汇编器接口
│          ├─c1                         client编译器(又称“C1”)
│          ├─ci                          动态编译器
│          ├─classfile                  类文件的处理(包括类加载和系统符号表等)
│          ├─code                       动态生成的代码的管理
│          ├─compiler                   从VM调用动态编译器的接口
│          ├─gc_implementation          GC的实现
│          │  ├─concurrentMarkSweep      Concurrent Mark Sweep GC的实现
│          │  ├─g1                       Garbage-First GC的实现(不使用老的分代式GC框架)
│          │  ├─parallelScavenge         ParallelScavenge GC的实现(server VM默认,不使用老的分代式GC框架)
│          │  ├─parNew                   ParNew GC的实现
│          │  └─shared                   GC的共通实现
│          ├─gc_interface               GC的接口
│          ├─interpreter                解释器,包括“模板解释器”(官方版在用)和“C++解释器”(官方版不在用)
│          ├─libadt                     一些抽象数据结构
│          ├─memory                     内存管理相关(老的分代式GC框架也在这里)
│          ├─oops                       HotSpot VM的对象系统的实现
│          ├─opto                       server编译器(又称“C2”或“Opto”)
│          ├─prims                      HotSpot VM的对外接口,包括部分标准库的native部分和JVMTI实现
│          ├─runtime                    运行时支持库(包括线程管理、编译器调度、锁、反射等)
│          ├─services                   主要是用来支持JMX之类的管理功能的接口
│          ├─shark                      基于LLVM的JIT编译器(官方版里没有使用)  
│          └─utilities                  一些基本的工具类
└─test                             单元测试

     

你可能感兴趣的:(Hotspot和Linux内核)