项目上线,发现集群机器每隔1小时会准时进行fullgc,JMC中显示了System.gc()触发了fullgc:
代码搜了一下自然是搜不到显示调用这个代码的(谁会这么干!拍死!!!)依赖jar包中到是有,但是看看也不像。
在大神的建议下,决定使用Btrace跟踪一下调用栈。
Pom依赖:
<dependency> <groupId>com.sun.tools.btrace</groupId> <artifactId>btrace-boot</artifactId> <version>1.2.3</version> </dependency>
java类:
import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.OnMethod; import static com.sun.btrace.BTraceUtils.jstack; import static com.sun.btrace.BTraceUtils.println; @BTrace public class GCBtrace { @OnMethod(clazz = "java.lang.System", method = "gc") public static void onSystemGC() { println("entered System.gc()"); jstack(); } }
Btrace包:https://github.com/btraceio/btrace
本地测试类:
public class GCTest { static int a = 1; public static void main(String[] args){ for (int a =0;a<10000;a++){ try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } // 触发gc a(); } } public static void a(){ b(); } public static void b(){ c(); } public static void c(){ System.out.println("第"+a+++"次触发gc"); System.gc(); } }
跟踪过程:
Step1. GCTest本地跑起来
Step2. Btrace放到固定目录下
Step3. GCBtrace.java 测试类 放到固定目录下
Step4. jps获取当前进程id
Step5. 进入btrace/bin文件夹下后,命令跟踪【./btrace 80543 /Users/***/GCBtrace.java】:
:bin ***$ ./btrace 80543 /Users/***/GCBtrace.java entered System.gc() java.lang.System.gc(System.java) btrace.GCTest.c(GCTest.java:40) btrace.GCTest.b(GCTest.java:36) btrace.GCTest.a(GCTest.java:33) btrace.GCTest.main(GCTest.java:28)
如上可以详细看到GC调用堆栈。
将Btarce和GCBtrace.java 拷贝到线上,即可查出到底是哪调用的System.gc().
特别注意:若植入btrace监控代码后,监控逻辑会一直在,直到重启应用。
参考:
1、 https://www.jianshu.com/p/dbb3a8b5c92f