仿网站教程,上海网络网站建,爱用建站官网,可以用qq登陆的wordpress1. STW是什么#xff1f;
Stop一the一World#xff0c;简称STW#xff0c;指的是Gc事件发生过程中#xff0c;会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停#xff0c;没有任何响应#xff0c;有点像卡死的感觉#xff0c;这个停顿称为STW。
2. STW出…1. STW是什么
Stop一the一World简称STW指的是Gc事件发生过程中会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停没有任何响应有点像卡死的感觉这个停顿称为STW。
2. STW出现的时机
可达性分析算法中枚举根节点GC Roots会导致所有Java执行线程停顿。目前主流的虚拟机采用的都是可达性算法算法的核心是利用根对象作为起始点根据对象之间的引用关系即引用链通过遍历引用链来判断对象的是否存活。然而可达性分析算法要求全过程都基于一个能保障一致性的快照中才能够进行分析简单来说就是必须全程冻结用户线程的运行。
3. 为什么必须冻结用户线程呢
因为如果用户线程和垃圾回收线程并发执行有可能会出现两个问题浮动垃圾 和 对象消失详情参考并发的可达性分析。
3.1 停顿的原因
a. 分析工作必须在一个能确保一致性的快照中进行 b. 一致性指整个分析期间整个执行系统看起来像被冻结在某个时间点上 c. 如果出现分析过程中对象引用关系还在不断变化则分析结果的准确性无法保证 d. 停顿的位置SafePoint 我也不理解
3.2 什么是 SafePoint SafePoint 就是一个安全点可以理解为用户线程执行过程中的一些特殊位置。SafePoint 保存了当前线程的 上下文当线程执行到这些位置的时候说明线程当前的状态是 确定的线程有哪些对象、使用了哪些内存。 因此只有用户线程处于 SafePoint 的时候线程才可以安全阻塞。 这意味着Stop-The-World 需要所有的用户线程处于 SafePoint。 3.3 SafePoint 在哪些位置 SafePoint 插入到代码的某些位置线程运行到 SafePoint 代码时将会主动去检查是否需要进入 SafePoint这个主动检查的过程被称为 Polling 。 ◉ 所有的非计数循环的末尾 防止循环体的执行时间太长一直进入不了 SafePoint ◉ 所有方法返回之前 ◉ 每条 Java 编译后的字节码的边界 SafePoint 的数量不能太少因为这将会导致进入 SafePoint 的前置时间过长以至于垃圾回收线程等待的时间太长。 SafePoint 的数量也不能太多过于频繁的 Polling 会有性能损耗。 3.4 如何实现 STW/SafePoint
首先Stop-The-World 需要所有的用户线程处于 SafePoint这意味着某个用户线程运行到 SafePoint其它用户线程可能处于不同的状态。
所有线程都到达GC Safepoint有两种方法
◉ 抢占式中断(Preemptive Suspension)
JVM会中断所有线程然后依次检查每个线程中断的位置是否为Safepoint如果不是则恢复用户线程让它执行至 Safepoint 再阻塞。◉ 主动式中断(Voluntary Suspension)
大部分 JVM 实现都是采用主动式中断需要阻塞用户线程的时候首先做一个标志用户线程会主动轮询这个标志位如果标志位处于就绪状态就自行中断。那么针对用户线程的各种状态需要怎么处理呢
正在执行字节码解释器检查当前用户线程的标志VM 线程调用以下方法阻塞线程。Interpreter::notice_safepoints()
正在运行 native 代码
如果 VM线程 发现一个当前用户线程正在执行 native 代码不会等待线程阻塞。当线程从 native 代码返回时检查 Safepoint 状态如果处于 SafePoint就直接阻塞线程。正在运行 JIT 编译好的代码
设置 Poling Page 为不可读当前用户线程发现该内存页不可读时就会被阻塞。
Poling Page
在 JVM 初始化启动的时候初始化的一个单独的内存页面这个页面是让运行的编译过的代码的线程进入阻塞状态的关键是一个全局的 Safepoint Polling Page。处于阻塞状态
在所有其他用户线程进入 SafePoint 之前一直阻塞当前用户线程。处于线程切换状态
一直轮询该用户线程状态直到线程处于阻塞状态。参考 JVM源码分析之安全点safepoint
3.5 SafePoint日志记录和分析
配置 -XX:PrintSafepointStatistics –XX:PrintSafepointStatisticsCount1 参数
-XX:PrintSafepointStatistics 打印安全点统计信息
-XX:PrintSafepointStatisticsCountn 设置打印安全点统计信息的次数3.6 日志分析
1. vmop 引发STW的原因以及触发时间本例中是GC。该项常见的输出有RevokeBias、BulkRevokeBias、Deoptimize、G1IncCollectionPause。
数字306936.812是虚拟机启动后运行的秒数。GC log可以根据该项内容定位Total time for which application threads…引发的详细信息。vmop 输出说明RevokeBias、BulkRevokeBias、偏向锁取消情况。Deoptimize、G1IncCollectionPause GC GC 执行情况。
2. total STW发生时JVM存在的线程数目。
3. initially_running STW发生时仍在运行的线程数这项是Spin阶段的 时间来源
4. wait_to_block STW需要阻塞的线程数目这项是block阶段的时间来源
5. sync spin block 其他。3.7 由日志可以看出safepoint的执行分为四个阶段
1. Spin阶段。因为jvm在决定进入全局safepoint的时候有的线程在安全点上而有的线程不在安全点上这个阶段是等待未在安全点上的用户线程进入安全点。
2. Block阶段。即使进入safepoint用户线程这时候仍然是running状态保证用户不在继续执行需要将用户线程阻塞。
3. Cleanup。这个阶段是JVM做的一些内部的清理工作。
4. VM Operation. JVM 执行的一些全局性工作例如 GC, 代码反优化。3.8 优化说明
分析 -XX:PrintSafepointStatistics –XX:PrintSafepointStatisticsCount1
产生的日志信息基本上STW的原因都是RevokeBias或者BulkRevokeBias。
这个是撤销偏向锁操作虽然每次暂停的 时间很短但是特别频繁出现也会很耗时。
一些高并发的系统中禁掉JVM偏向锁优化可以提升系统的吞吐量。
禁用偏向锁的参数为: -XX:-UseBiasedLocking3.9 引起长时间STW原因
- GC
- RevokeBias 撤销偏向锁操作也会消耗很长时间。在高并发系统中建议禁用偏向锁。
- 撤销偏向锁增加 -XX:-UseBiasedLocking 虚拟机参数4. 示例代码
被STW中断的应用程序线程会在完成GC之后恢复频繁的中断会让用户感觉像是网速不快造成的电影卡顿一样所以我们要减少STW的发生STW事件和采用哪款GC无关所有的GC都有这个事件。哪怕是G1也不能完全避免STW情况发生只能说垃圾回收器越来越优秀回收效率越来越高尽可能地缩短了暂停时间。STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下把用户正常的工作线程全部停掉。开发中采用System.gc会导致STW的发生。
package com.zishi.jvm;import java.util.ArrayList;
import java.util.List;public class StopTheWorldDemo {public static class WorkThread extends Thread {Listbyte[] list new ArrayListbyte[]();public void run() {try {while (true) {for(int i 0;i 1000;i){byte[] buffer new byte[1024];list.add(buffer);}if(list.size() 10000){list.clear();System.gc();//会触发full gc进而会出现STW事件}}} catch (Exception ex) {ex.printStackTrace();}}}public static class PrintThread extends Thread {public final long startTime System.currentTimeMillis();public void run() {try {while (true) {// 每秒打印时间信息long t System.currentTimeMillis() - startTime;System.out.println(t / 1000 . t % 1000);Thread.sleep(1000);}} catch (Exception ex) {ex.printStackTrace();}}}public static void main(String[] args) {WorkThread w new WorkThread();PrintThread p new PrintThread();w.start();p.start();}
}W线程当中的GC触发了STW进而干扰了P线程有规律性打印。打印变得杂乱无章 打印输出
0.0
1.100
2.103
3.112
4.122
5.134
6.143