做者:郑雨迪html
来源:极客时间《深刻拆解Java虚拟机》java
做为一位Java程序员,在尽情享受Java虚拟机带来好处的同时,咱们还应该去了解和思考“这些技术特性是如何实现的”,去了解最底层的原理。只有熟悉JVM,你才能在遇到 OutOfMemory等异常时,不会一筹莫展,不会一脸懵逼地上网找解决办法,最后就算改了几个启动参数解决了问题,也仍是云里雾里。git
此次,我会从我专栏里提取了学习Java虚拟机的X大知识要点,助力你们深刻理解JVM,知其然也知其因此然。 不过你在看知识点以前,最好能问问本身你会怎么回答,再和我提供的内容作对比,这样子提高会比较明显。
程序员
我将以HotSpot虚拟机为例,从虚拟机以及底层硬件两个角度,来分享解析。github
执行Java代码首先须要将它编译而成的class文件加载到Java虚拟机中。加载后的Java类会被存放于方法区中。实际运行时,虚拟机会执行方法区内的代码。算法
若是你熟悉X86的话,你会发现这和段式内存管理中的代码段相似。并且,Java虚拟机一样也在内存中划分出堆和栈来存储运行时数据。不一样的是,Java虚拟机会将栈细分为面向Java方法的Java方法栈,面向用C++写的native方法的本地方法栈,以及存放各个线程执行位置的PC寄存器。 缓存
在运行过程当中,每当调用进入一个Java方法,Java虚拟机会在当前线程的Java方法栈中生成一个栈帧,用以存放局部变量以及字节码的操做数。这个栈帧的大小是提早计算好的,并且Java虚拟机不要求栈帧在内存空间里连续分布。安全
当退出当前执行的方法时,不论是正常返回仍是异常返回,Java虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。性能优化
Java字节码没法直接执行。所以,Java虚拟机须要将字节码翻译成机器码。微信
在HotSpot里面,上述翻译过程有两种形式:第一种是解释执行,至关于同声传译,即每解析一条字节码,便翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),则至关于线下翻译,即将整个方法中所包含的字节码统一翻译成机器码后在执行。
前者的优点在于无需等待编译,然后者的优点在于实际运行速度更快。HotSpot默认采用混合模式,综合了解释执行和即时编译二者的优势。它会先解释执行字节码,然后将其中反复执行的热点代码,以方法为单位进行即时编译。
Java虚拟机加载Java类的过程可分为加载、连接以及初始化三大步骤。
加载是指查找字节流,而且据此建立类的过程。加载须要借助类加载器,在Java虚拟机中,类加载器使用了双亲委派模型,即接收到加载请求时,会先将请求转发给父类加载器。
连接,是指将建立成的类合并至Java虚拟机中,使之可以执行的过程。连接还分验证、准备和解析三个阶段,分别完成“验证被加载类是否知足Java虚拟机约束”,“为被加载类静态字段分配内存”,以及“将被加载类中的符号引用解析成为实际引用”的工做。其中,Java虚拟机规范并不要求解析阶段必定要在连接步骤中完成。
初始化,则是为标记为常量值的字段赋值,以及执行方法的过程。类的初始化仅会被执行一次,这个特性被用来实现单例的延迟初始化。
Java虚拟机中的垃圾回收器采用可达性分析来探索全部存活的对象。它从一系列GC Roots出发,边标记边探索全部被引用的对象。为了防止在标记过程当中堆栈的状态发生改变,Java虚拟机采起安全点机制来实现Stop-The-World操做,暂停其余非垃圾回收线程。
回收垃圾对象的内存共有三种基础算法,分别为:会形成内存碎片的清除算法、性能开销较大的压缩算法、以及堆使用效率较低的复制算法。
一般来讲,Java虚拟机会采用分代回收的思想,将堆划分为新生代和老年代,而且经过在不一样代中应用不一样的垃圾回收算法。
传统的作法是将新生代再划分为Eden区和两个大小一致的Survivor区。在只针对新生代的Minor GC中,Eden区和非空Survivor区的存活对象会被复制到空的Survivor区中,当Survivor区中的存活对象复制次数超过必定数值时,它将被晋升至老年代。
由于Minor GC只针对新生代进行垃圾回收,因此在枚举GC Roots的时候,它须要考虑从老年代到新生代的引用。为了不扫描整个老年代,Java虚拟机引入了名为卡表的技术,大体地标出可能存在老年代到新生代的引用的内存区域。
G1垃圾回收器将堆划分为多个等大的区域,每一个区域均可以充当Eden区,Survivor区或者老年代区。G1会优先收集垃圾最多的区域,从而最大化垃圾回收的效益。这也是Garbage First名字的由来。
Java 11中引入的实验性垃圾回收器ZGC,仅在扫描GC Roots时请求Stop-The-World,暂停应用线程。所以,它宣称可将GC暂停时间控制在10ms如下。ZGC暂时没有应用分代回收的思路,将整个堆空间当作一块,其代价是垃圾回收CPU消耗较高。
在现代计算机系统中,代码一般不会按照书写顺序执行。形成这一状况的缘由有三个,分别为编译器的重排序,处理器的乱序执行,以及内存系统的重排序。
之内存系统重排序为例,在多处理器体系架构下,每一个处理器均可能缓存了一部分数据。因为时刻保持缓存数据与内存数据同步的性能代价太大,所以部分体系架构可能容许缓存数据与内存数据不一样步。这对Java程序的影响即是,两个不一样的Java线程在同一时间内看到的同一块内存地址中的值可能不一样。
Java内存模型是针对上述问题而提出的一套规范,用以容许Java程序员更为细致地定义Java程序的内存行为。它经过定义了一系列的happens-before操做,让应用程序开发者可以轻易地表达不一样线程的操做之间的内存可见性。
在遵照Java内存模型的前提下,即时编译器以及底层体系架构可以调整内存访问操做,以达到性能优化的效果。若是开发者没有正确地利用happens-before规则,那么将可能致使数据竞争。
Java内存模型是经过内存屏障来禁止重排序的。对于即时编译器来讲,内存屏障将限制它所能作的重排序优化。对于处理器来讲,内存屏障会致使缓存的刷新操做。
个人专栏《深刻拆解Java虚拟机》已完结,很是感谢在我专栏完结以前的16000多名订阅用户,在未了解完整内容的状况下,毅然订阅了个人专栏。为不辜负你们的信任,我几乎每篇专栏都会大量阅读HotSpot的源代码,和同事讨论实现背后的设计理念,在这个过程当中,我也发现了一些HotSpot中的Bug,或者年久失修的代码,又或者是设计不合理的地方。这大概也可以算做写专栏和我本职工做重叠的地方吧。
专栏虽然到此已经结束了,可是并不表明你对Java虚拟机学习的中止。我想,专栏的内容仅仅是为你打开了JVM学习的大门,里面的风景,仍是须要你本身来探索。在文章的后面,我列出了一系列的Java虚拟机技术的相关博客和阅读资料,你仍然能够继续加餐。
你能够关注国内几位Java虚拟机大咖的微信公众号:
R大,我的认为是中文圈子里最了解Java虚拟机设计实现的人,你能够关注他的[知乎帐号](https://www.zhihu.com/people/rednaxelafx);
[你假笨](https://open.weixin.qq.com/qr/code?username=lovestblog),原阿里Java虚拟机团队成员,现[PerfMa](http://www.perfma.com/) CEO;
[江南白衣](https://open.weixin.qq.com/qr/code?username=jnby1978),惟品会资深架构师;
[占小狼](https://open.weixin.qq.com/qr/code?username=whywhy_zj),美团基础架构部技术专家;
[杨晓峰](https://open.weixin.qq.com/qr/code?username=gh_9f3b2a4e2a74),前甲骨文首席工程师。
若是英文阅读没问题的话,你能够关注[Cliff Click](http://cliffc.org/blog/)、[Aleksey Shipilv](https://shipilev.net/)(他的[JVM Anatomy Park](https://shipilev.net/jvm-anatomy-park/)十分有趣)和[Nitsan Wakart](http://psy-lob-saw.blogspot.com/)的博客。
你也能够关注[Java Virtual Machine Language Submit](http://openjdk.java.net/projects/mlvm/jvmlangsummit/)和[Oracle Code One](https://www.oracle.com/code-one/index.html)(前身是JavaOne大会)中关于Java虚拟机的演讲,以便掌握Java的最新发展动向。
固然,若是对GraalVM感兴趣的话,你能够订阅咱们团队的[博客](https://medium.com/graalvm)。以后我会考虑逐一进行翻译。
至于其余阅读材料,你能够参考R大的这份[书单](https://www.douban.com/doulist/2545443/),或者这个[汇总贴](https://github.com/deephacks/awesome-jvm)。
若是本专栏已经激发了你对Java虚拟机的学习热情,那么我建议你着手阅读HotSpot源代码,而且回馈OpenJDK开源社区。这种回馈并不必定是提交patch,也能够是bug report或者改进建议等等。
道阻且长,努力加餐~!
能够说,Java虚拟机就是每一位Java工程师进阶加薪的利器,你想往上升,你想深刻技术,不想一直停留在简单开发,或者你在作Java性能分析、调优工做时,那么,Java虚拟机绝对是一把助力的利剑。
推荐个人完结专栏:《深刻拆解Java虚拟机》给你。