精华内容
下载资源
问答
  • 每日一面 - JVM 何时会 Stop the world

    万次阅读 2021-01-17 08:22:49
    这个定时主要是为了一些没必要立刻 Stop the world 的任务执行,可以设置-XX:GuaranteedSafepointInterval=0关闭这个定时,我推荐是关闭。 由于 jstack,jmap 和 jstat 等命令,也就是 Signal Dispatcher 线程要处理...
    1. 定时进入 SafePoint:每经过-XX:GuaranteedSafepointInterval 配置的时间,都会让所有线程进入 Safepoint,一旦所有线程都进入,立刻从 Safepoint 恢复。这个定时主要是为了一些没必要立刻 Stop the world 的任务执行,可以设置-XX:GuaranteedSafepointInterval=0关闭这个定时,我推荐是关闭。
    2. 由于 jstack,jmap 和 jstat 等命令,也就是 Signal Dispatcher 线程要处理的大部分命令,都会导致 Stop the world:这种命令都需要采集堆栈信息,所以需要所有线程进入 Safepoint 并暂停。
    3. 偏向锁取消(这个不一定会引发整体的 Stop the world,参考JEP 312: Thread-Local Handshakes):Java 认为,锁大部分情况是没有竞争的(某个同步块大多数情况都不会出现多线程同时竞争锁),所以可以通过偏向来提高性能。即在无竞争时,之前获得锁的线程再次获得锁时,会判断是否偏向锁指向我,那么该线程将不用再次获得锁,直接就可以进入同步块。但是高并发的情况下,偏向锁会经常失效,导致需要取消偏向锁,取消偏向锁的时候,需要 Stop the world,因为要获取每个线程使用锁的状态以及运行状态。
    4. Java Instrument 导致的 Agent 加载以及类的重定义:由于涉及到类重定义,需要修改栈上和这个类相关的信息,所以需要 Stop the world
    5. Java Code Cache相关:当发生 JIT 编译优化或者去优化,需要 OSR 或者 Bailout 或者清理代码缓存的时候,由于需要读取线程执行的方法以及改变线程执行的方法,所以需要 Stop the world
    6. GC:这个由于需要每个线程的对象使用信息,以及回收一些对象,释放某些堆内存或者直接内存,所以需要 Stop the world
    7. JFR 的一些事件:如果开启了 JFR 的 OldObject 采集,这个是定时采集一些存活时间比较久的对象,所以需要 Stop the world。同时,JFR 在 dump 的时候,由于每个线程都有一个 JFR 事件的 buffer,需要将 buffer 中的事件采集出来,所以需要 Stop the world。
    8. 其他的事件,不经常遇到,可以参考 JVM 源码 vmOperations.hpp:
    #define VM_OPS_DO(template)                       \
      template(None)                                  \
      template(Cleanup)                               \
      template(ThreadDump)                            \
      template(PrintThreads)                          \
      template(FindDeadlocks)                         \
      template(ClearICs)                              \
      template(ForceSafepoint)                        \
      template(ForceAsyncSafepoint)                   \
      template(DeoptimizeFrame)                       \
      template(DeoptimizeAll)                         \
      template(ZombieAll)                             \
      template(Verify)                                \
      template(PrintJNI)                              \
      template(HeapDumper)                            \
      template(DeoptimizeTheWorld)                    \
      template(CollectForMetadataAllocation)          \
      template(GC_HeapInspection)                     \
      template(GenCollectFull)                        \
      template(GenCollectFullConcurrent)              \
      template(GenCollectForAllocation)               \
      template(ParallelGCFailedAllocation)            \
      template(ParallelGCSystemGC)                    \
      template(G1CollectForAllocation)                \
      template(G1CollectFull)                         \
      template(G1Concurrent)                          \
      template(G1TryInitiateConcMark)                 \
      template(ZMarkStart)                            \
      template(ZMarkEnd)                              \
      template(ZRelocateStart)                        \
      template(ZVerify)                               \
      template(HandshakeOneThread)                    \
      template(HandshakeAllThreads)                   \
      template(HandshakeFallback)                     \
      template(EnableBiasedLocking)                   \
      template(BulkRevokeBias)                        \
      template(PopulateDumpSharedSpace)               \
      template(JNIFunctionTableCopier)                \
      template(RedefineClasses)                       \
      template(UpdateForPopTopFrame)                  \
      template(SetFramePop)                           \
      template(GetObjectMonitorUsage)                 \
      template(GetAllStackTraces)                     \
      template(GetThreadListStackTraces)              \
      template(GetFrameCount)                         \
      template(GetFrameLocation)                      \
      template(ChangeBreakpoints)                     \
      template(GetOrSetLocal)                         \
      template(GetCurrentLocation)                    \
      template(ChangeSingleStep)                      \
      template(HeapWalkOperation)                     \
      template(HeapIterateOperation)                  \
      template(ReportJavaOutOfMemory)                 \
      template(JFRCheckpoint)                         \
      template(ShenandoahFullGC)                      \
      template(ShenandoahInitMark)                    \
      template(ShenandoahFinalMarkStartEvac)          \
      template(ShenandoahInitUpdateRefs)              \
      template(ShenandoahFinalUpdateRefs)             \
      template(ShenandoahDegeneratedGC)               \
      template(Exit)                                  \
      template(LinuxDllLoad)                          \
      template(RotateGCLog)                           \
      template(WhiteBoxOperation)                     \
      template(JVMCIResizeCounters)                   \
      template(ClassLoaderStatsOperation)             \
      template(ClassLoaderHierarchyOperation)         \
      template(DumpHashtable)                         \
      template(DumpTouchedMethods)                    \
      template(PrintCompileQueue)                     \
      template(PrintClassHierarchy)                   \
      template(ThreadSuspend)                         \
      template(ThreadsSuspendJVMTI)                   \
      template(ICBufferFull)                          \
      template(ScavengeMonitors)                      \
      template(PrintMetadata)                         \
      template(GTestExecuteAtSafepoint)               \
      template(JFROldObject)                          \
    

    每日一刷,轻松提升技术,斩获各种offer:

    image

    展开全文
  • 等等还有很多 很多人问为什么GC的时候要暂停(stop-the-world)整个程序,为什么不能并发的执行GC呢?GC本质上是一种权衡,Stop-the-world 是为了GC吞吐量(在给定CPU时间内多少垃圾可以被收集器清除?),便不是说...

    并发编程的许多困难都源于对象生存期问题,当对象在线程之间传递时,要确保它们安全地释放就变得很麻烦。因此GC可以使得并发编程变得容易。但是GC也是一个挑战,但是一次实现,就可以解决人们手动管理内存的麻烦(C语言),大大提高的开发效率和避免了许多Bug。

    但是GC也是有成本的,他会影响程序的效率,GC是一个非常挑战的工作,很多计算机科学家在上面耗费了数十年不断的提升效率。

    GC算法设计时,会考虑几个重要指标:

    (1) 程序吞吐量:GC对程序效率的影响,也就花费在GC的时间和程序处理正常业务的时间比;

    (2) GC吞吐量:单位时间内垃圾回收的数量;
    (3) 暂停时间:Stop-the-world 的时间;
    (4) 并发:垃圾回收机制如何使用多核;
    等等还有很多

    很多人问为什么GC的时候要暂停(stop-the-world)整个程序,为什么不能并发的执行GC呢?GC本质上是一种权衡,Stop-the-world 是为了GC吞吐量(在给定CPU时间内多少垃圾可以被收集器清除?),便不是说GC必须STW,你也可以选择降低运行速度但是可以并发执行的收集算法,这取决于你的业务。

    比如:你做金融交易类的项目,分秒必争,那可以选择并行的方式。如果你是一种后台任务,比如数据处理,那你可以选择STW类型算法,使 GC 的吞吐量得到最高。

    两类算法最终的权衡指标就GC效率:程序工作时间与执行收集时间的比率。

    没有单一的算法在所有方面都完美,语言也不可能知道程序的业务类型,这也就是“GC调优”存在的原因。这也是科学的基础规律。

    展开全文
  • 什么是 STOP THE WORLD

    千次阅读 2020-03-25 20:14:28
    当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行标记和清除。 在执行垃圾收集算法时,Java应用程序的其他所有线程都...

    等待所有用户线程进入安全点后并阻塞,做一些全局性操作的行为。

    当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行标记和清除。

    在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止native代码可以执行,但不能与JVM交互;这些现象多半是由于gc引起。

    展开全文
  • jvm的stop the world时间过长优化

    千次阅读 2019-07-03 11:18:16
    现象:小米有一个比较大的公共离线HBase集群,用户很多,每天有大量的MapReduce或Spark离线分析任务在进行访问,同时有很多其他在线集群Replication过来的数据写入,集群因为读写压力较大,且离线分析任务对延迟不...

    现象:小米有一个比较大的公共离线HBase集群,用户很多,每天有大量的MapReduce或Spark离线分析任务在进行访问,同时有很多其他在线集群Replication过来的数据写入,集群因为读写压力较大,且离线分析任务对延迟不敏感,所以其G1GC的MaxGCPauseMillis设置是500ms。

    但是随着时间的推移,我们发现了一个新的现象,线程的STW时间可以到3秒以上,但是实际GC的STW时间却只有几百毫秒!

    打印GC日志

    • -XX:+PrintGC

    • -XX:+PrintGCDetails

    • -XX:+PrintGCApplicationStoppedTime

    • -XX:+PrintHeapAtGC

    • -XX:+PrintGCDateStamps

    • -XX:+PrintAdaptiveSizePolicy

    • -XX:+PrintTenuringDistribution

    具体的日志log示例如下:[Times: user=1.51 sys=0.67, real=0.14 secs]

    2019-06-25T12:12:43.376+0800: 3448319.277: Total time for which application threads were stopped: 2.2645818 seconds, Stopping threads took: xxx seconds

    -XX:+PrintGCApplicationStoppedTime会打出类似上面的日志,这个stopped时间是JVM里所有STW的时间,不止GC。我们遇到的现象就是stopped时间远大于上面的GC real耗时,比如GC只耗时0.14秒,但是线程却stopped了2秒多。这个时候大概率就是GC时线程进入Safepoint耗时过长,所以需要2个新的GC参数来打印出Safepoint的情况。

    打印Safepoint相关日志

    • -XX:+PrintSafepointStatistics

    • -XX:PrintSafepointStatisticsCount=1

    需要注意的是Safepoint的情况是打印到标准输出里的,具体的日志log示例如下:

    vmop    [threads: total initially_running wait_to_block] 65968.203: ForceAsyncSafepoint [931   1   2]

    这部分日志是时间戳,VM Operation的类型,以及线程概况,比如上面就显示有2个线程在等待进入Safepoint:

    [time: spin block sync cleanup vmop] page_trap_count[2255  0  2255 11  0]  1

    接下来的这部分日志是到达Safepoint时的各个阶段以及执行操作所花的时间:

    spin:因为JVM在决定进入全局Safepoint的时候,有的线程在Safepoint上,而有的线程不在Safepoint上,这个阶段是等待未在Safepoint上的用户线程进入Safepoint。

    block:即使进入Safepoint,用户线程这时候仍然是running状态,保证用户不在继续执行,需要将用户线程阻塞

    sync:spin+block的耗时

    所以上面的日志就是说,有2个线程进入Safepoint特别慢,其他线程等待这2个线程进入Safepoint等待了2255ms。打印进入Safepoint慢的线程

    • -XX:+SafepointTimeout

    • -XX:SafepointTimeoutDelay=2000

    这两个参数的意思是当有线程进入Safepoint超过2000毫秒时,会认为进入Safepoint超时了,这时会打出来哪些线程没有进入Safepoint,具体日志如下:# SafepointSynchronize::begin: Timeout detected:

    # SafepointSynchronize::begin: Timed out while spinning to reach a safepoint.# SafepointSynchronize::begin: Threads which did not reach the safepoint:# "RpcServer.listener,port=24600" #32 daemon prio=5 os_prio=0 tid=0x00007f4c14b22840 nid=0xa621 runnable [0x0000000000000000]java.lang.Thread.State: RUNNABLE# SafepointSynchronize::begin: (End of list)

    从上面的日志可以看出来是RpcServer.listener进入Safepoint耗时过长,那么该如何解决这个问题呢?这就需要了解一点GC和Safepoint的背景知识了。

    GC及Safepoint

    GC

    GC(Garabage Collection):垃圾回收,是Java这种自动内存管理语言中的关键技术。GC要解决的三个关键问题是:哪些内存可以回收?什么时候回收?以及如何回收?对于哪些内存可以回收,常见的有引用计数算法和可达性分析算法来判断对象是否存活。可达性分析算法的基本思路是从GC Roots出发向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则称该对象不可达,也就是说可以回收了。常见的GC Roots对象有:

    • 虚拟机栈中引用的对象

    • 方法区中静态属性引用的对象

    • 方法区中常量引用的对象

    • Native方法栈中引用的对象

    Safepoint

    Java虚拟机HotSpot的实现中,使用一组称为OopMap的数据结构来存放对象引用,从而可以快速且准确的完成GC Root扫描。但程序执行的过程中,引用关系随时都可能发生变化,而HotSpot虚拟机只会在特殊的指令位置才会生成OopMap来记录引用关系,这些位置便被称为Safepoint。换句话说,就是在Safepoint这个点上,虚拟机对于调用栈、寄存器等一些重要的数据区域里什么地方包含了什么引用是十分清楚的,这个时候是可以很快完成GC Roots的扫描和可达性分析的。HotSpot会在所有方法的临返回之前,以及所有Uncounted loop的循环回跳之前放置Safepoint。当需要GC时候,虚拟机会首先设置一个标志,然后等待所有线程进入Safepoint,但是不同线程进入Safepoint的时间点不一样,先进入Safepoint的线程需要等待其他线程全部进入Safepoint,所以Safepoint是会导致STW的。

    Counted loop

    JVM认为比较短的循环,所以不会放置Safepoint,比如用int作为index的循环。与其对应的是Uncounted loop。

    Uncounted loop

    JVM会在每次循环回跳之前放置Safepoint,比如用long作为index的循环。所以一个常见的问题是当某个线程跑进了Counted loop时,JVM启动了GC,然后需要等待这个线程把循环跑完才能进入Safepoint,如果这个循环是个大循环,且循环内执行的比较慢,而且不存在其他函数调用产生其他Safepoint,这时就需要等待该线程跑完循环才能从其他位置进入Safepoint,这就导致了其他线程可能会长时间的STW。

    解 决 问 题

    UseCountLoopSafepoints-XX:+UseCountedLoopSafepoints这个参数会强制在Counted loop循环回跳之前插入Safepoint,也就是说即使循环比较短,JVM也会帮忙插入Safepoint了,用于防止大循环执行时间过长导致进入Safepoint卡住的问题。但是这个参数在JDK8上是有Bug的,可能会导致JVM Crash,而且是到JDK9才修复的,具体参考JDK-8161147。鉴于我们使用的是OpenJDK8,所以只能放弃该方案。

    修改循环index为long型

    上面的Safepoint Timeout日志已经明确指出了,进Safepoint慢的线程是RpcServer里的listener线程,所以在仔细读了一遍代码之后,发现其调用到的函数cleanupConnections里有个大循环,具体代码如下:

    /** cleanup connections from connectionList. Choose a random range     * to scan and also have a limit on the number of the connections     * that will be cleanedup per run. The criteria for cleanup is the time     * for which the connection was idle. If 'force' is true then all     * connections will be looked at for the cleanup.     * @param force all connections will be looked at for cleanup     */private void cleanupConnections(boolean force) {  if (force || numConnections > thresholdIdleConnections) {    long currentTime = System.currentTimeMillis();    if (!force && (currentTime - lastCleanupRunTime) < cleanupInterval) {      return;    }    int start = 0;    int end = numConnections - 1;    if (!force) {      start = rand.nextInt() % numConnections;      end = rand.nextInt() % numConnections;      int temp;      if (end < start) {        temp = start;        start = end;        end = temp;      }    }    int i = start;    int numNuked =0;    while (i <= end) {      Connection c;      synchronized (connectionList) {        try {          c = connectionList.get(i);        } catch (Exception e) {return;}      }        if (c.timedOut(currentTime)) {        if (LOG.isDebugEnabled())          LOG.debug(getName() + ": disconnecting client " + c.getHostAddress());        closeConnection(c);        numNuked++;        end--;        //noinspection UnusedAssignment        c = null;        if (!force && numNuked == maxConnectionsToNuke) break;      }      else i++;    }    lastCleanupRunTime = System.currentTimeMillis();  }}

    如注释所说,它会从connectionList中随机选择一个区间,然后遍历这个区间内的connection,并清理掉其中已经timeout的connection。但是,connectionList有可能很大,因为出问题的集群是个离线集群,会有多个MR/Spark Job来进行访问,而每个Job又会同时起多个Mapper/Reducer/Executer来进行访问,其每一个都是一个HBase Client,而Client为了性能考虑,默认连同一个RegionServer的connection数使用了配置4,这就导致connectionList里面可能存在大量的从client连接过来的connection。更为关键的是,这里循环的index是int类型,所以这是一个Counted loop,JVM不会在每次循环回跳的时候插入Safepoint。当GC发生时,如果RpcServer的listener线程刚好执行到该函数里的循环内部时,则必须等待循环跑完才能进入Safepoint,而此时其他线程也必须一起等着,所以从现象上看就是长时间的STW。    

    Debug的过程很曲折,但问题解决起来其实很简单,就是把这里的循环index从int类型改为long型即可,这样JVM会在每次循环回跳前插入Safepoint,即使GC时候执行到了循环内部,也只需执行到单次循环体结束便可以进入Safepoint,无需等待整个循环跑完。

     

    至此,问题得到解决。

    最后,本文重点不是介绍Safepoint原理,主要是对一次线上真实Case的的踩坑记录,希望文中的JVM参数配置和Debug过程可以对大家有所帮助,如有错误,欢迎指正。

     

    参考文档:

      https://bugs.openjdk.java.net/browse/JDK-8161147

      http://calvin1978.blogcn.com/articles/safepoint.html

      https://xhao.io/2018/02/safepoint-1/

      https://www.zhihu.com/question/29268019

     《深入理解Java虚拟机》周志明著

    展开全文
  • 什么是stop the world 在gc事件发生过程中,会产生应用的停顿,停顿产生时整个应用程序线程都会被暂停,没有任何响应,有点像卡死的感觉,这个停顿称为STW 为什么需要stop the world 可达性分析算法中,枚举根节点...
  • Stop the world

    千次阅读 2018-03-02 14:53:16
    我们都知道,在虚拟机进行GC的时候会需要让所用的线程都停止工作,等待他GC完成,那么他是如何保证所有线程全部都停止工作的呢? 只有当所有线程都跑到了安全点,或者进入安全区域之后,才会进行GC ...
  • 一、GC算法    ① 引用计数法: 老牌垃圾回收算法,通过引用计数来回收垃圾。(Java不用) ... 问题之一:很难处理循环...三、Stop-The-World现象 转载于:https://www.cnblogs.com/NoYone/p/8971239.html
  • JVM GC中Stop the world案例实战

    万次阅读 2016-08-31 00:00:34
    GC中Stop the world案例实战
  • JVM进阶(八)——Stop The World(停顿类型STW)   小伙伴还记得上一篇中我们留下的一个问题吗?什么是停顿类型!经过前几章的学习,我们知道垃圾回收首先是要经过标记的。对象被标记后就会根据不同的区域采用不同...
  • 但是有些时候对于虚拟机来说采用Stop the world机制是无法避免的,例如采用复制算法时,为了保证在复制存活的对象的时候,对象的一致性,必然要使应用程序被挂起。 但是随着java虚拟机的发展,HotSpot虚拟机团队为...
  • 5. 问题如期而至,发现stop the world前几秒钟的IO利用率就已经到了100%,有了这个证据我们大概率怀疑是IO导致的stop the world。但是具体是哪个进程IO比较多呢,就我们本身的业务来说没有IO读,IO写的量大约100K/s...
  • 理解CMS GC日志 本文翻译自: ...加入自己的思考,特别是为什么remark要stop the world? 准备工作 JVM的GC日志的主要参数包括如下几个: -XX:+PrintGC 输出GC日志 -XX:+PrintGCDetails 输出GC
  • JAVA Stop The World

    2018-08-16 16:37:14
     虚拟机的解决方法就是在一些特定指令位置设置一些“安全点”,当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行标记...
  • stop the world

    2019-01-07 18:26:30
    危害
  • 这些问题一般和 SafePoint 还有 Stop the World 有关。 什么是 SafePoint?什么是 Stop the world?他们之间有何关系? 我们先来设想下如下场景: 当需要 GC 时,需要知道哪些对象还被使用,或者已经不被使用可以...
  • GC日志中的stop-the-world

    千次阅读 2016-12-23 17:29:35
    通常使用下面的JVM选项在GC日志中打印”stop-the-world”(STW)暂停时间。 -XX:+PrintGCApplicationStoppedTime 但是在GC日志中看,会发现有许多这样的暂停时间,时间很短,肯定不是垃圾回收引起的。 Total time...
  • 本文基于 Go 1.13。在某些垃圾回收器算法中,“停止世界”(Stop the World: STW,下同)是跟踪内存使用最重要的阶段,它会停止程序的...
  • 为什么会有stop the world

    千次阅读 2019-06-17 11:04:52
    首先,我们知道java中的引用主要存在于方法区和堆栈区。 当jvm运行对象存活判定算法的时候,如果当前环境下,对象之间的引用还在发生变化,那么这个算法几乎没法执行,所以常常需要STW来维持秩序。...
  • JVM为什么需要Stop-The-World? 上一篇Java虚拟机面试准备(二)垃圾收集算法和垃圾收集器中介绍了判断对象是否存活需要进行可达性分析,此时可能其它进程已经更新对象的引用,那么可能出现误报和漏报,误报问题不大,可以...
  • JVM优化系列-Stop-The-World实战

    千次阅读 2019-12-25 16:12:53
    所以在垃圾清理的过程中这样的停顿被称为是Stop-The-World。 文章目录 示例 分析问题 总结 示例 public class StopWorldTest { public static class MyThread extends Thread { ...
  • 原文讲述了jvm发生STW可能的原因(不仅是GC),以及在日志中的体现(主要是对gc.log中,total time for which application threads were stopped这行的解释)。...Logging Stop-the-world Pause...
  • jvm的stop-the-world机制

    2019-12-03 10:15:17
    https://blog.51cto.com/11009785/2401604
  • "ParNew" is a stop-the-world, copying collector which uses multiple GC threads. It differs from "Parallel Scavenge" in that it has enhancements that make it usable with CMS. For example, "ParNew" ...
  • Stop-the-World,简称STW 1、指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉,这个停顿称为STW。 (1)可达性分析算法中枚举根节点(GC ...
  • GC的时候为什么要StopTheWorld(全局停顿)??? 在GC的时候,进行标记过程时,可达性分析必须要在一个可以保证一致性的快照中执行!也就是说, 不可以出现在分析过程中对象的引用关系还在不断变化的情况 ,该点...
  • Java中Stop-The-World机制简称STW,是在执行垃圾收集算法时,Java应用程序的其他所有线程都被挂起(除了垃圾收集帮助器之外)。Java中一种全局暂停现象,全局停顿,所有Java代码停止,native代码可以执行,但不能与...
  • JVM的STW(stop the world)机制及调优案例

    千次阅读 2020-08-25 15:26:37
    STW(stop the world)是什么 1、stop the world指的是GC事件发生过程中,会产生应用程序的停顿。停顿产生时整个应用程序线程都会被暂停,没有任何响应, 有点像卡死的感觉,这个停顿称为STW。Java中一种全局暂停现象,...
  •   虚拟机的解决方法就是在一些特定指令位置设置一些“安全点”,当程序运行到这些“安全点”的时候就会暂停所有当前运行的线程(Stop The World 所以叫STW),暂停后再找到“GC Roots”进行关系的组建,进而执行...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 113,848
精华内容 45,539
关键字:

stopworld