关于java:JVM整理三

49次阅读

共计 3489 个字符,预计需要花费 9 分钟才能阅读完成。

JVM 介绍

执行引擎

执行引擎蕴含解释器、jit 编译器、垃圾回收器, 所以 java 又称为是半编译半解释的语言. 执行引擎的工作就是将字节码指令解释 / 编译为利用平台上的本地机器指令, 能力让 Java 程序运行起来.

解释器

JVM 启动时, 会依据预约义的标准对字节码采纳逐行解释的形式执行, 将每条字节码文件中的内容编译为对应平台的本地机器指令执行.(重点: 不须要期待编译, 立刻执行, 但执行须要逐行解释)

JIT 编译器

JVM 将字节码间接编译成和本地机器平台相干的机器语言, 加载热点代码.(重点: 有个编译的过程须要期待, 但执行速度快)

为什么要有编译器还要有解释器?

因为解释器须要每一行指令都去翻译,这样效率十分低下。只能是那些一开始曾经确定好的程序,当程序启动的时候,解释器能够马上应用,省去编译的工夫,立刻执行。而编译器,编译的工夫远远大于解释器,尽管能够很好防止函数被解释执行,而是将整个函数体编译成为机器码,每次函数执行时,只执行编译后的机器码即可,这种形式能够使执行效率大幅度晋升。所以各有利弊,在不同的场景能够应用。

设置程序执行办法

默认状况下 JVM 采纳解释器和即时编译器并存的架构, 当然也能够依据具体的利用场景, 通过配置命令的形式指定 JVM 齐全采纳解释器执行, 还是齐全采纳即时编译器执行.
-Xint: 齐全采纳解释器模式
-Xcomp: 齐全采纳即时编译器模式执行程序
-Xmixed: 默认模式
如图:

热点探测

JVM 会依据代码被调用的频率来判断这块代码或这行代码是否是热点代码, 如果达到肯定阈值则会被 JIT 编译器探测到, 而后将其间接编译为对应平台的本地机器指令, 以此晋升 java 程序的执行性能.
能够通过配置指令形式 -XX:CompileThreshold=10000 设置对应阈值, 默认值为 10000, 如图:

热度衰减

办法调用计数器统计并不是办法被调用的相对次数, 而是一个绝对的执行频率, 即一段时间之内办法被调用的次数. 当超过肯定的工夫限度, 如果办法的调用次数依然不足以让它提交给即时编译器编译, 那这个办法的调用计数器就会被缩小一半, 这个过程称为办法调用计数器热度衰减, 而这段时间就称为该办法统计的半衰周期.
能够通过 -XX:-UseCounterDecay 来敞开热度衰减, 默认是开启的.
半衰周期 (CounterHalfLifeTime) 没有提供指令形式进行设置. 查问 jdk 源码(https://github.com/openjdk/jdk/blob/jdk8-b120/hotspot/src/share/vm/runtime/globals.hpp), 该参数为开发参数, 默认值为 30, 单位为秒. 如图:

垃圾收集器

jdk8 有 Serial 收集器、Parallel 收集器、CMS 收集器、G1 收集器. 掂量垃圾收集器的三项重要指标: 内存占用、吞吐量和提早. 三者独特形成了一个不可能三角. 一般来说低提早的垃圾收集器的吞吐量比拟低, 高吞吐的垃圾收集器的延迟时间比拟高.

按年老代与老年代应用的垃圾回收器辨别:

年老代: serial,parnew,parallel scavenge.
老年代: serial old,cms,parallel old.

按提早和吞吐量辨别:

低提早优先:cms,g1
吞吐量优先:parallel old

按单线程和多线程辨别:

单线程:serial,serial old
多线程:parnew,cms,parallel scavenge,parallel old,g1

按年老代和老年代组合应用

如图: 红色虚线局部为 jdk8 已废除,jdk9 已去除, 绿色虚线局部 jdk14 为已废除,CMS 在 jdk14 中已删除.

Serial 回收器

Serial 收集器运行示意图:

介绍

(1)Serial 收集器是最根底、历史最悠久的收集器, 已经(在 JDK 1.3.1 之前)是 HotSpot 虚拟机新生代收集器的惟一抉择.
(2)大家只看名字就可能猜到,这个收集器是一个单线程工作的收集器, 它在进行垃圾收集时, 必须暂停其余所有工作线程, 直到它收集完结.

实用场景

小型物理机, 运行在客户端模式下的虚拟机,Serial 收集器是个不错的抉择, 因为没有线程交互的开销, 分心做垃圾收集天然能够取得最高的单线程收集效率.
能够通过 -XX:+UseSerialGC 开启应用 Serial 收集器, 如图:

Parallel 回收器

Parallel 收集器运行示意图:

介绍

(1) Parallel 与 Serial 相比, 它是一款多线程工作的垃圾收集器, 能够充沛的利用 cpu 资源.
(2) 与 Parnew 相比, 它的关注指标是达到一个可管制的吞吐量(吞吐量 = 用户利用程序运行的工夫 /(利用程序运行的工夫 + 垃圾回收的工夫)).
(3) Parallel Scavenge 和 Parallel Old 是 jdk8 默认的垃圾收集器.

实用场景

如果对于收集器运作不太理解,手工优化存在艰难的话,应用 Parallel Scavenge 收集器配合自适应调节策略,把内存治理的调优工作交给虚拟机去实现兴许是一个很不错的抉择。
只须要把根本的内存数据设置好(如 -Xmx 设置最大堆),而后应用 -XX:MaxGCPauseMillis 参数(更关注最大进展工夫)或 -XX:GCTimeRatio(更关注吞吐量)参数给虚拟机设立一个优化指标,那具体细节参数的调节工作就由虚拟机实现了。
能够通过 -XX:+UseParallelGC 或 -XX:+UseParallelOldGC 应用 Parallel 收集器.

CMS 回收器

CMS(Concurrent Mark Sweep)收集器运行示意图:

介绍

(1) CMS 收集器是以获取最短进展工夫为指标的收集器.
(2) CMS 收集器是基于标记 - 革除算法实现的, 整个过程能够分为四个步骤:
1)初始标记(CMS initial mark)
有 STW; 初始标记仅仅只是标记一下 GCRoots 能间接关联到的对象, 速度很快.
2)并发标记(CMS concurrent mark)
并发标记阶段就是从 GC Roots 的间接关联对象开始遍历整个对象图的过程, 这个过程耗时较长然而不须要进展用户线程, 能够与 GC 线程一起并发运行.
3)从新标记(CMS remark)
有 STW; 从新标记阶段是为了修改并发标记期间, 因用户程序持续运作而导致标记产生变动的那一部分对象的标记记录.
4)并发革除(CMS concurrent sweep)
清理删除掉标记阶段判断的曾经死亡的对象, 因为不须要挪动存活对象, 所以这个阶段也是能够与用户线程同时并发执行的.
STW(stop the world)介绍: 示意在垃圾收集器在此工作期间, 其余业务线程都会暂停工作, 应用程序会有卡顿.

实用场景

应用程序比拟重视用户的应用体验,CMS 是以获取最短回收进展工夫为指标.
能够通过 -XX:+UseConcMarkSweepGC 应用 CMS 收集器, 它是和 Parnew 收集器组合应用的, 如图:

CMS 毛病

(1) CMS 收集器无奈解决“浮动垃圾”(Floating Garbage), 有可能呈现“Con-current Mode Failure”失败而导致另一次 Full GC, 即让 Serial Old 收集器来解决.
(2) 标记革除会产生大量空间碎片. 空间碎片过多, 将会给大对象的调配带来麻烦.

G1 回收器

G1 收集器内存示意图:

介绍

(1) G1 创始的基于 Region 的堆内存布局是它可能实现垃圾优先回收指标的要害.G1 不再保持固定大小以及固定数量的分代区域划分, 而是把间断的 Java 堆划分为多个大小相等的独立区域(Region), 每一个 Region 都能够依据须要, 表演新生代的 Eden 空间、Survivor 空间, 或者老年代空间.
(2) G1(Garbage First)收集器会跟踪各个 Region 外面的垃圾沉积的大小, 保护一个优先级列表, 依据用户设定容许的收集进展工夫(应用 -XX:MaxGCPauseMillis 配置进展工夫, 默认 200 毫秒), 优先解决垃圾沉积较大的区域.
(3) 依据下面介绍,G1 收集器和 CMS 收集器一样, 它也是以低提早优先的收集器

实用场景

在小内存利用上 CMS 的体现会优于 G1, 然而在大内存利用上 G1 大多能施展其劣势, 当然这也不是相对的, 不同利用须要理论测试能力得出最合适的论断.

总结

只有最合适的垃圾收集器, 没有最好的垃圾收集器. 这也是 HotSpot 虚拟机提供实现那么多种不同收集器的起因. 垃圾收集器调优是重点也是难点, 须要开发者积攒大量 JVM 底层原理并结合实际应用程序状况作出绝对应的参数调整.

JVM 总结

HotSpot 的 JVM 文章就介绍到这了, 大家有什么问题须要探讨的能够留言评论! 谢谢

[下一篇 介绍 java 关键字]

正文完
 0