18、JVM实战:垃圾回收之STW


159

Stop The World

Stop一the一World,简称STW,指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW。

举例:
*可达性分析算法中枚举根节点(GC Roots)会导致所有Java执行线程停顿。

停顿的原因:

1、 分析工作必须在一个能确保一致性的快照中进行;
2、 一致性指整个分析期间整个执行系统看起来像被冻结在某个时间点上V;
3、 如果出现分析过程中对象引用关系还在不断变化,则分析结果的准确性无法保证;

特点描述:

  • 被STW中断的应用程序线程会在完成GC之后恢复,频繁中断会让用户感觉像是网速不快造成电影卡带一样, 所以我们需要减少STW的发生。
  • STW事件和采用哪款GC无关,所有的GC都有这个事件。
  • 哪怕是G1也不能完全避免Stop一the一world情况发生,只能说垃圾回收器越来越优秀,回收效率越来越高,尽可能地缩短了暂停时间。
  • STW是JVM在后台自动发起和自动完成的。在用户不可见的情况下,把用户正常的工作线程全部停掉。
  • 开发中不要采用System.gc();会导致Stop一the一world的发生。

STW示例代码:

public class StopTheWorldDemo {
   
     
    public static class WorkThread extends Thread {
   
     
        List<byte[]> list = new ArrayList<byte[]>();

        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();
    }
}

P线程执行每隔一秒打印一次,当没有w线程时的输出秒数间隔规律为1秒。

但当同时运行w线程时,W线程当中的GC触发了STW,进而干扰了P线程有规律性打印。打印变得杂乱无章

打印输出:
*