我怎么知道谁在 spark 流程序中调用了 System.gc()?
How can I know who call System.gc() in spark streaming program?
我的 spark streaming 程序中的 GC 时间太长了。在GC日志中发现程序中有人调用了System.gc()
。我没有在我的代码中调用 System.gc()
。所以调用者应该是我用的api
我将 -XX:-DisableExplicitGC
添加到 JVM 并解决了这个问题。但是,我想知道谁调用了 System.gc()
.
我尝试了一些方法。
- 使用
jstack
。但是GC不是那么频繁,很难dump调用方法的线程。
- 我添加了在 JProfiler 中调用方法
java.lang.System.gc()
时添加线程转储的触发器。但是好像不行。
如何知道谁在 spark streaming 程序中调用了 System.gc()?
您不会用 jstack
捕获 System.gc
,因为在 stop-the-world 暂停期间 JVM 不接受来自动态附加工具的连接,包括 jstack
、jmap
, jcmd
和类似的。
可以通过 async-profiler:
追踪 System.gc
来电者
预先开始分析:
$ profiler.sh start -e java.lang.System.gc <pid>
发生一个或多个 System.gc
后,停止分析并打印堆栈跟踪:
$ profiler.sh stop -o traces <pid>
示例输出:
--- Execution profile ---
Total samples : 6
Frame buffer usage : 0.0007%
--- 4 calls (66.67%), 4 samples
[ 0] java.lang.System.gc
[ 1] java.nio.Bits.reserveMemory
[ 2] java.nio.DirectByteBuffer.<init>
[ 3] java.nio.ByteBuffer.allocateDirect
[ 4] Allocate.main
--- 2 calls (33.33%), 2 samples
[ 0] java.lang.System.gc
[ 1] sun.misc.GC$Daemon.run
在上面的例子中,System.gc
从两个地方被调用了6次。两者都是 JDK 内部强制垃圾收集的典型情况。
第一个来自java.nio.Bits.reserveMemory
。当没有足够的可用内存分配新的直接 ByteBuffer 时(由于 -XX:MaxDirectMemorySize
限制),JDK 强制 full GC 回收无法访问的直接 ByteBuffer。
第二个来自 GC Daemon 线程。这由 Java RMI 运行时定期调用。例如,如果您使用 JMX 远程,则每小时自动启用一次定期 GC。这可以通过 -Dsun.rmi.dgc.client.gcInterval
系统 属性.
进行调整
我的 spark streaming 程序中的 GC 时间太长了。在GC日志中发现程序中有人调用了System.gc()
。我没有在我的代码中调用 System.gc()
。所以调用者应该是我用的api
我将 -XX:-DisableExplicitGC
添加到 JVM 并解决了这个问题。但是,我想知道谁调用了 System.gc()
.
我尝试了一些方法。
- 使用
jstack
。但是GC不是那么频繁,很难dump调用方法的线程。 - 我添加了在 JProfiler 中调用方法
java.lang.System.gc()
时添加线程转储的触发器。但是好像不行。
如何知道谁在 spark streaming 程序中调用了 System.gc()?
您不会用 jstack
捕获 System.gc
,因为在 stop-the-world 暂停期间 JVM 不接受来自动态附加工具的连接,包括 jstack
、jmap
, jcmd
和类似的。
可以通过 async-profiler:
追踪System.gc
来电者
预先开始分析:
$ profiler.sh start -e java.lang.System.gc <pid>
发生一个或多个
System.gc
后,停止分析并打印堆栈跟踪:$ profiler.sh stop -o traces <pid>
示例输出:
--- Execution profile --- Total samples : 6 Frame buffer usage : 0.0007% --- 4 calls (66.67%), 4 samples [ 0] java.lang.System.gc [ 1] java.nio.Bits.reserveMemory [ 2] java.nio.DirectByteBuffer.<init> [ 3] java.nio.ByteBuffer.allocateDirect [ 4] Allocate.main --- 2 calls (33.33%), 2 samples [ 0] java.lang.System.gc [ 1] sun.misc.GC$Daemon.run
在上面的例子中,
System.gc
从两个地方被调用了6次。两者都是 JDK 内部强制垃圾收集的典型情况。第一个来自
java.nio.Bits.reserveMemory
。当没有足够的可用内存分配新的直接 ByteBuffer 时(由于-XX:MaxDirectMemorySize
限制),JDK 强制 full GC 回收无法访问的直接 ByteBuffer。第二个来自 GC Daemon 线程。这由 Java RMI 运行时定期调用。例如,如果您使用 JMX 远程,则每小时自动启用一次定期 GC。这可以通过
-Dsun.rmi.dgc.client.gcInterval
系统 属性. 进行调整