五大部分总览
- 宏观介绍整个JAVA技术体系(Java和JVM的发展历程、模块化)、JDK的编译
- 介绍JVM自动内存管理:JVM内存区域的划分,Stackoverflow和OOM现象及其原因、 常见的垃圾收集算法以及垃圾回收器的工作原理
- 虚拟机执行子系统:类文件结构、虚拟类加载机制、虚拟机字节码执行引擎
- 程序的编译以及代码的优化:泛型、自动装箱、条件编译等语法糖的原理、虚拟机热点探测方法、Hotspot即时编译
- Java高效并发的原理:虚拟机内存模型以及线程安全
JAVA历史&JVM历史(一笔带过,感兴趣的可以详细看下。对于把握整个JAVA技术脉络还是有些帮助的。
- JAVA历史
1997 JDK1.1 版的技术代表:JAR、JDBC ;JAVA语法:内部类、反射
1998 JDK1.2版 首次把JAVA技术体系拆成三个方向,JAVA虚拟机,JIT编译器
1999 Hotspot虚拟机被Sun公司收购并在JDK1.3之后成为SunJDK的默认虚拟机
2002 JDK1.4发布,正则表达式、NIO,同年微软.NET Framework发布
2004 JDK1.5 发布提供 java.util.concurrent并发包 - JVM历史
Sun Classic VM 远古虚拟机
世界第一台商用Java虚拟机
特点:只能使用纯解释器方式执行Java代码如果使用JIT必须外挂,假如外挂,JIT编译器就完全接管了虚拟机的执行系统,解释器就不再工作了。缺点:解释器和编译器不能协同工作导致‘Java语言很慢’。
Exact VM
Hotspot VM
自己编译JDK
- 环境: centos 7
- 安装Mercurial代码版本管理工具:yum -y install mercurial
- hg clone https://hg.openjdk.java.net/jdk7u/jdk7u-dev/
- cd jdk7u-dev 进入jdk7u-dev目录
- chmod +x get_source.sh 赋予可执行权限
- 运行脚本获得代码,网络不稳定(代码如缺失retry)
编译前的环境准备
安装gcc、gcc-c++
yum install -y gcc gcc-c++
安装cups-devel (unix打印系统)
yum install -y cups-devel
安装alsa-lib-devel
yum install -y alsa-lib-devel
安装X图形库
yum install -y libXrender libXrender-devel libXi-devel libXt-devel libXtst-devel
安装freetype字体库
yum install -y freetype freetype-devel
安装bootstrap JDK
yum install -y java-1.6.0-openjdk java-1.6.0-openjdk-devel
安装ant
yum install -y ant ant-nodeps
设置环境变量并做编译前的环境检查make sanity
- vim setenv.sh
#!/bin/bash
#clear settings if you have ever setup
unset CLASSPAHT
unset JAVA_HOME
#select language, required
export LANG=C
#bootsrap JDK path installed, required
export ALT_BOOTDIR=/usr/local/jdk1.7.0_79
#setup freetype
export ALT_FREETYPE_LIB_PATH=/usr/local/lib
export ALT_FREETYPE_HEADERS_PATH=/usr/local/include
#setup ant path
export ANT_HOME=/root/apache-ant-1.9.7
#dowload dependencies automatically
export ALLOW_DOWNLOADS=ture
#setup number of compiled threads same to cpus
export HOTSPOT_BUILD_JOBS=1
export ALT_PARALLEL_COMPILE_JOBS=1
export SKIP_COMPARE_IMAGES=true
export USE_PRECOMPILED_HEADER=true
#setup what you want to compile
export BUILD_LANGTOOLS=true
#export BUILD_JAXP=false
#export BUILD_JAXWS=false
#export BUILD_CORBA=false
export BUILD_HOTSPOT=true
export BUILD_JDK=true
#setup arch=64 if your cpu is 64 or arch=32
export ARCH_DATA_MODEL=64
#setup version
#export SKIP_DEBUG_BUILD=false
#export SKIP_FASTDEBUG_BUILD=true
#export DEBUG_NAME=debug
BUILD_DEPLOY=false
#cancel build install package
BUILD_INSTALL=false
#setup output DIR
export ALT_OUTPUTDIR=/usr/local/jdk7-dev/build
- 执行脚本 最好用source
- 环境检查 make sanity
[xxxx@xxxxx jdk7u-dev]$ sudo make sanity
( cd ./jdk/make && \
make sanity HOTSPOT_IMPORT_CHECK=false JDK_TOPDIR=/data/work/jdk7u-dev/jdk JDK_MAKE_SHARED_DIR=/data/work/jdk7u-dev/jdk/make/common/shared EXTERNALSANITYCONTROL=true SOURCE_LANGUAGE_VERSION=7 TARGET_CLASS_VERSION=7 MILESTONE=internal BUILD_NUMBER=b00 JDK_BUILD_NUMBER=b00 FULL_VERSION=1.7.0-internal-root_2019_10_29_18_25-b00 PREVIOUS_JDK_VERSION=1.6.0 JDK_VERSION=1.7.0 JDK_MKTG_VERSION=7 JDK_MAJOR_VERSION=1 JDK_MINOR_VERSION=7 JDK_MICRO_VERSION=0 PREVIOUS_MAJOR_VERSION=1 PREVIOUS_MINOR_VERSION=6 PREVIOUS_MICRO_VERSION=0 ARCH_DATA_MODEL=64 COOKED_BUILD_NUMBER=0 ALT_OUTPUTDIR=/data/work/jdk7u-dev/build/linux-amd64 ALT_LANGTOOLS_DIST=/data/work/jdk7u-dev/build/linux-amd64/langtools/dist ALT_CORBA_DIST=/data/work/jdk7u-dev/build/linux-amd64/corba/dist ALT_JAXP_DIST=/data/work/jdk7u-dev/build/linux-amd64/jaxp/dist ALT_JAXWS_DIST=/data/work/jdk7u-dev/build/linux-amd64/jaxws/dist ALT_HOTSPOT_IMPORT_PATH=/data/work/jdk7u-dev/build/linux-amd64/hotspot/import BUILD_HOTSPOT=true ; )
INFO: ENABLE_FULL_DEBUG_SYMBOLS=1
INFO: /usr/bin/objcopy cmd found so will create .debuginfo files.
INFO: STRIP_POLICY=min_strip
INFO: ZIP_DEBUGINFO_FILES=1
/bin/sh: line 0: [: /bin/sh:: integer expression expected
/bin/sh: line 0: [: /bin/sh:: integer expression expected
/bin/sh: line 0: [: /NO_BOOTDIR/bin/java:: integer expression expected
/bin/sh: line 0: [: /NO_BOOTDIR/bin/java:: integer expression expected
/bin/sh: line 0: [: No: integer expression expected
/bin/sh: line 0: [: No: integer expression expected
make[1]: Entering directory `/data/work/jdk7u-dev/jdk/make'
INFO: ENABLE_FULL_DEBUG_SYMBOLS=1
INFO: /usr/bin/objcopy cmd found so will create .debuginfo files.
INFO: STRIP_POLICY=min_strip
INFO: ZIP_DEBUGINFO_FILES=1
make[1]: Leaving directory `/data/work/jdk7u-dev/jdk/make'
Build Machine Information:
build machine = ES-077-031.bigdata.ly
Build Directory Structure:
CWD = /data/work/jdk7u-dev
TOPDIR = .
LANGTOOLS_TOPDIR = ./langtools
JAXP_TOPDIR = ./jaxp
JAXWS_TOPDIR = ./jaxws
CORBA_TOPDIR = ./corba
HOTSPOT_TOPDIR = ./hotspot
JDK_TOPDIR = ./jdk
Build Directives:
BUILD_LANGTOOLS = true
BUILD_JAXP = true
BUILD_JAXWS = true
BUILD_CORBA = true
BUILD_HOTSPOT = true
BUILD_JDK = true
DEBUG_CLASSFILES =
DEBUG_BINARIES =
Hotspot Settings:
HOTSPOT_BUILD_JOBS =
HOTSPOT_OUTPUTDIR = /data/work/jdk7u-dev/build/linux-amd64/hotspot/outputdir
HOTSPOT_EXPORT_PATH = /data/work/jdk7u-dev/build/linux-amd64/hotspot/import
Bootstrap Settings:
BOOTDIR = /NO_BOOTDIR
ALT_BOOTDIR =
BOOT_VER = /bin/sh: /NO_BOOTDIR/bin/java: No such file or directory [requires at least 1.6]
OUTPUTDIR = /data/work/jdk7u-dev/build/linux-amd64
ALT_OUTPUTDIR = /data/work/jdk7u-dev/build/linux-amd64
ABS_OUTPUTDIR = /data/work/jdk7u-dev/build/linux-amd64
Build Tool Settings:
SLASH_JAVA = /NOT-SET
ALT_SLASH_JAVA =
VARIANT = OPT
JDK_DEVTOOLS_DIR = /NOT-SET/devtools
ALT_JDK_DEVTOOLS_DIR =
ANT_HOME =
UNIXCOMMAND_PATH = /bin/
ALT_UNIXCOMMAND_PATH =
COMPILER_PATH = /usr/bin/
ALT_COMPILER_PATH =
DEVTOOLS_PATH = /usr/bin/
ALT_DEVTOOLS_PATH =
UNIXCCS_PATH = /usr/ccs/bin/
ALT_UNIXCCS_PATH =
USRBIN_PATH = /usr/bin/
ALT_USRBIN_PATH =
COMPILER_NAME = GCC4
COMPILER_VERSION = GCC4
CC_VER = 4.8.5 [requires at least 4.3.0]
ZIP_VER = 3.0 [requires at least 2.2]
UNZIP_VER = 6.00 [requires at least 5.12]
ANT_VER = 1.9.4 [requires at least 1.7.1]
TEMPDIR = /data/work/jdk7u-dev/build/linux-amd64/tmp
Build Directives:
OPENJDK = true
USE_HOTSPOT_INTERPRETER_MODE =
PEDANTIC =
DEV_ONLY =
NO_DOCS =
NO_IMAGES =
TOOLS_ONLY =
INSANE =
COMPILE_APPROACH = parallel
PARALLEL_COMPILE_JOBS = 2
ALT_PARALLEL_COMPILE_JOBS =
FASTDEBUG =
COMPILER_WARNINGS_FATAL = false
COMPILER_WARNING_LEVEL =
SHOW_ALL_WARNINGS =
INCREMENTAL_BUILD = false
CC_HIGHEST_OPT =
CC_HIGHER_OPT =
CC_LOWER_OPT =
CXXFLAGS = -O2 -fPIC -DCC_NOEX -W -Wall -Wno-unused -Wno-parentheses -fno-omit-frame-pointer -D_LITTLE_ENDIAN
CFLAGS = -O2 -fno-strict-aliasing -fPIC -W -Wall -Wno-unused -Wno-parentheses -pipe -fno-omit-frame-pointer -D_LITTLE_ENDIAN
BOOT_JAVA_CMD = /NO_BOOTDIR/bin/java -XX:-PrintVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-LogVMOutput -Xmx512m -Xms512m -XX:PermSize=32m -XX:MaxPermSize=160m
BOOT_JAVAC_CMD = /NO_BOOTDIR/bin/javac -J-XX:ThreadStackSize=1536 -J-XX:-PrintVMOptions -J-XX:+UnlockDiagnosticVMOptions -J-XX:-LogVMOutput -J-Xmx512m -J-Xms512m -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -encoding ascii -source 6 -target 6 -XDignore.symbol.file=true
BOOT_JAR_CMD = /NO_BOOTDIR/bin/jar
BOOT_JARSIGNER_CMD = /NO_BOOTDIR/bin/jarsigner
JAVAC_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-amd64/bin/javac -J-XX:ThreadStackSize=1536 -J-XX:-PrintVMOptions -J-XX:+UnlockDiagnosticVMOptions -J-XX:-LogVMOutput -J-Xmx512m -J-Xms512m -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -source 7 -target 7 -encoding ascii -Xbootclasspath:/data/work/jdk7u-dev/build/linux-amd64/classes
JAVAH_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-amd64/bin/javah -bootclasspath /data/work/jdk7u-dev/build/linux-amd64/classes
JAVADOC_CMD = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-amd64/bin/javadoc -J-XX:-PrintVMOptions -J-XX:+UnlockDiagnosticVMOptions -J-XX:-LogVMOutput -J-Xmx512m -J-Xms512m -J-XX:PermSize=32m -J-XX:MaxPermSize=160m -bootclasspath /data/work/jdk7u-dev/build/linux-amd64/classes
Build Platform Settings:
USER = root
PLATFORM = linux
ARCH = amd64
LIBARCH = amd64
ARCH_FAMILY = amd64
ARCH_DATA_MODEL = 64
ARCHPROP = amd64
ALSA_VERSION = 1.1.8
OS_VERSION = 4.11.1-1.el7.elrepo.x86_64 [requires at least 2.6]
OS_VARIANT_NAME = RedHat
OS_VARIANT_VERSION =
MB_OF_MEMORY = 257102
GNU Make Settings:
MAKE = make
MAKE_VER = 3.82 [requires at least 3.81]
MAKECMDGOALS = sanity
MAKEFLAGS = w
SHELL = /bin/sh
Target Build Versions:
JDK_VERSION = 1.7.0
MILESTONE = internal
RELEASE = 1.7.0-internal
FULL_VERSION = 1.7.0-internal-root_2019_10_29_18_25-b00
BUILD_NUMBER = b00
External File/Binary Locations:
USRJDKINSTANCES_PATH = /opt/java
BUILD_JDK_IMPORT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries
ALT_BUILD_JDK_IMPORT_PATH =
JDK_IMPORT_PATH = /NOT-SET/re/jdk/1.7.0/promoted/latest/binaries/linux-amd64
ALT_JDK_IMPORT_PATH =
LANGTOOLS_DIST =
ALT_LANGTOOLS_DIST = /data/work/jdk7u-dev/build/linux-amd64/langtools/dist
CORBA_DIST =
ALT_CORBA_DIST = /data/work/jdk7u-dev/build/linux-amd64/corba/dist
JAXP_DIST =
ALT_JAXP_DIST = /data/work/jdk7u-dev/build/linux-amd64/jaxp/dist
JAXWS_DIST =
ALT_JAXWS_DIST = /data/work/jdk7u-dev/build/linux-amd64/jaxws/dist
HOTSPOT_DOCS_IMPORT_PATH = /NO_DOCS_DIR
ALT_HOTSPOT_DOCS_IMPORT_PATH =
HOTSPOT_IMPORT_PATH = /data/work/jdk7u-dev/build/linux-amd64/hotspot/import
ALT_HOTSPOT_IMPORT_PATH = /data/work/jdk7u-dev/build/linux-amd64/hotspot/import
HOTSPOT_SERVER_PATH = /data/work/jdk7u-dev/build/linux-amd64/hotspot/import/jre/lib/amd64/server
ALT_HOTSPOT_SERVER_PATH =
CACERTS_FILE = ./../src/share/lib/security/cacerts
ALT_CACERTS_FILE =
CUPS_HEADERS_PATH = /usr/include
ALT_CUPS_HEADERS_PATH =
OpenJDK-specific settings:
FREETYPE_HEADERS_PATH = /usr/include
ALT_FREETYPE_HEADERS_PATH =
FREETYPE_LIB_PATH = /usr/lib
ALT_FREETYPE_LIB_PATH =
Previous JDK Settings:
PREVIOUS_RELEASE_PATH =
ALT_PREVIOUS_RELEASE_PATH =
PREVIOUS_JDK_VERSION = 1.6.0
ALT_PREVIOUS_JDK_VERSION =
PREVIOUS_JDK_FILE =
ALT_PREVIOUS_JDK_FILE =
PREVIOUS_JRE_FILE =
ALT_PREVIOUS_JRE_FILE =
PREVIOUS_RELEASE_IMAGE =
ALT_PREVIOUS_RELEASE_IMAGE =
WARNING: LANG has been set to en_US.UTF-8, this can cause build failures.
Try setting LANG to 'C'.
Sanity check passed.
最后sudo make ALT_BOOTDIR=${jdk路径} (编译openjdk源码不仅需要jre环境也需要jdk环境)
关于编译过程中几个问题
- 刚开始我是直接使用make命令,export ALT_BOOTDIR=${jdk路径} 但在centos7 系统中编译openjdk-7u40,执行make sanity通过,但是在实行make时报了Error running /NO_BOOTDIR/bin/javac compiler错误
BUILD FAILED
/data/work/jdk7u-dev/langtools/make/build.xml:860: Error running /NO_BOOTDIR/bin/javac compiler
由于openJDK默认值安装了jre,也就是java运行环境,并没有安装java开发环境,所以导致打包失败。
执行一下命令:
yum install java-1.7.0-openjdk-devel
然后又定位了java环境、查看环境变量配置,因为我里面同时有多个版本的java环境。
发现并不是问题的直接原因
,最终直接在编译的时候直接指定同版本的jdk进行编译: sudo make ALT_BOOTDIR=${jdk路径} 解决了问题
- 另外一些问题都可以通过错误提示进行针对性的解决
缺少哪个包直接yum install 就行了,然后make clean make sanity 再编译。 有些可能是之前下载C和C++语言相关的包(gcc g++)没下载全导致的,重新下载下多试几次。
编译成功结果
接下来,你就可以执行下简单的java代码尝试下了:)
/**
* @author LD
* @create time 2019-10-30 15:13
*/
public class HelloJAVA {
public static void main(String[] args) {
System.out.println("Hello OpenJDK");
}
}
参考文献
在定位问题、解决问题中,筛选并参考了几篇帮助较大的文章,觉得有必要Mark一下。ps:在此过程中粉了rednaxelafx
大牛,C++造轮子有轮子哥JAVA造轮子的是rednaxelafx,我更欣赏低调的大牛。
https://www.cnblogs.com/xidongyu/p/5722122.html
http://www.voidcn.com/article/p-zgthnemz-bpb.html
http://www.linxiaoming.me/2016/10/12/OpenJDK%E7%BC%96%E8%AF%91/
https://www.linuxidc.com/Linux/2018-10/155041.htm
https://hllvm-group.iteye.com/group/topic/35385
https://www.iteye.com/blog/rednaxelafx-1549577
https://axboy.github.io/java/2018/12/21/openjdk7-centos/
https://www.jianshu.com/p/eaa2756e93d0
第二章 自动内存管理机制
- Java虚拟机运行时的内存分布
-
需要明确几个问题
- 哪些区域是伴随虚拟机进程的生命周期,哪些区域是依赖用户线程启动
- 哪些区域是线程共享的,哪些区域是线程私有的
线程私有的
: 程序计数器、虚拟机栈 (局部变量)
线程共享的
: 堆(新生代、老年代)、方法区(静态变量) -
Java虚拟机栈
在这个区域有一个异常情况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出
StackOverflowError
- 实践
设置运行时栈的大小:
-Xss256k
代码
- 实践
-
Java堆
Java 虚拟机管理的内存中最大的一块,该区域唯一目的就是存放对象实例。
- 该区域是垃圾收集器管理的主要区域因此也被称为‘GC堆’,Java堆可以细分为:新生代和老年代;再细致分:Eden区、From survivor区、To survivor区。
- 根据Java虚拟机规范规定,Java堆只要逻辑连续即可,如果堆中没有内存了将会抛出
OOM
- 实践
设置运行时堆的大小:
-Xmx5m
代码
-
方法区
和堆一样是线程共享区,存储加载类信息、常量(运行常量池)、静态变量等数据
HotSpot虚拟机在Java堆中创建对象全过程
- 当虚拟机接收到new一个对象的指令时,首先去常量池定位这个类的符号引用并且检查该类是否被加载、解析初始化过。没有则执行类加载过程。