Java虚拟机必学之四大知识要点你掌握了吗?

做为一位 Java 程序员,在尽情享受 Java 虚拟机带来好处的同时,咱们还应该去了解和思考“这些技术特性是如何实现的”,去了解最底层的原理。只有熟悉 JVM,你才能在遇到 OutOfMemory 等异常时,不会一筹莫展,不会一脸懵逼地上网找解决办法,最后就算改了几个启动参数解决了问题,也仍是云里雾里。程序员

此次,我提取了学习 Java 虚拟机的 X 大知识要点,助力你们深刻理解 JVM,知其然也知其因此然。 不过你在看知识点以前,最好能问问本身你会怎么回答,再和我提供的内容作对比,这样子提高会比较明显。算法

第一大知识要点:Java 字节码是如何在虚拟机里运行的?缓存

我将以 HotSpot 虚拟机为例,从虚拟机以及底层硬件两个角度,来分享解析。安全

一、从虚拟机视角来看性能优化

执行 Java 代码首先须要将它编译而成的 class 文件加载到 Java 虚拟机中。加载后的 Java 类会被存放于方法区中。实际运行时,虚拟机会执行方法区内的代码。架构

若是你熟悉 X86 的话,你会发现这和段式内存管理中的代码段相似。并且,Java 虚拟机一样也在内存中划分出堆和栈来存储运行时数据。不一样的是,Java 虚拟机会将栈细分为面向 Java 方法的 Java 方法栈,面向用 C++ 写的 native 方法的本地方法栈,以及存放各个线程执行位置的 PC 寄存器。并发

 

在运行过程当中,每当调用进入一个 Java 方法,Java 虚拟机会在当前线程的 Java 方法栈中生成一个栈帧,用以存放局部变量以及字节码的操做数。这个栈帧的大小是提早计算好的,并且 Java 虚拟机不要求栈帧在内存空间里连续分布。app

当退出当前执行的方法时,不论是正常返回仍是异常返回,Java 虚拟机均会弹出当前线程的当前栈帧,并将之舍弃。分布式

二、从硬件视角来看微服务

Java 字节码没法直接执行。所以,Java 虚拟机须要将字节码翻译成机器码。

在 HotSpot 里面,上述翻译过程有两种形式:第一种是解释执行,至关于同声传译,即每解析一条字节码,便翻译成机器码并执行;第二种是即时编译(Just-In-Time compilation,JIT),则至关于线下翻译,即将整个方法中所包含的字节码统一翻译成机器码后在执行。

 

前者的优点在于无需等待编译,然后者的优点在于实际运行速度更快。HotSpot 默认采用混合模式,综合了解释执行和即时编译二者的优势。它会先解释执行字节码,然后将其中反复执行的热点代码,以方法为单位进行即时编译。

第二大知识要点:Java 虚拟机是如何加载 Java 类的?

Java 虚拟机加载 Java 类的过程可分为加载、连接以及初始化三大步骤。

加载是指查找字节流,而且据此建立类的过程。加载须要借助类加载器,在 Java 虚拟机中,类加载器使用了双亲委派模型,即接收到加载请求时,会先将请求转发给父类加载器。

 

连接,是指将建立成的类合并至 Java 虚拟机中,使之可以执行的过程。连接还分验证、准备和解析三个阶段,分别完成“验证被加载类是否知足 Java 虚拟机约束”,“为被加载类静态字段分配内存”,以及“将被加载类中的符号引用解析成为实际引用”的工做。其中,Java 虚拟机规范并不要求解析阶段必定要在连接步骤中完成。

初始化,则是为标记为常量值的字段赋值,以及执行 <clinit> 方法的过程。类的初始化仅会被执行一次,这个特性被用来实现单例的延迟初始化。

第三大知识要点: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 程序员更为细致地定义 Java 程序的内存行为。它经过定义了一系列的 happens-before 操做,让应用程序开发者可以轻易地表达不一样线程的操做之间的内存可见性。

在遵照 Java 内存模型的前提下,即时编译器以及底层体系架构可以调整内存访问操做,以达到性能优化的效果。若是开发者没有正确地利用 happens-before 规则,那么将可能致使数据竞争。

顺便在此给你们推荐一个Java架构方面的交流学习群:698581634,里面会分享一些资深架构师录制的视频资料:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系,主要针对Java开发人员提高本身,突破瓶颈,相信你来学习,会有提高和收获。在这个群里会有你须要的内容  朋友们请抓紧时间加入进来吧。

相关文章
相关标签/搜索