梦想还是要有的,万一忘了咋办?

0%

JavaAgent

JavaAgent
JavaAgent是一个JVM插件,一种专门精心制作的.jar文件,它能够利用jvm提供的 Instrumentation API(Java1.5开始提供)。Agent分为2种:主程序运行前的Agent,主程序之后运行的Agent(Jdk1.6增加)。

主程序之前的Agent

写一个Agent

1
2
3
4
5
6
public class PreAgent{
//方法名称必须是premain
public static void premain(String agentArgs,Instrumentation inst){
System.out.println("permain : "+agentArgs);
}
}

主程序

1
2
3
4
5
public class Main{
public static void main(String[] args){
System.out.println("main");
}
}

编写MANIFEST.MF文件

1
2
3
4
5
group 'com.hardydou.learn'
artifactId 'preAgent'
version '1.0-SNAPSHOT'
premainClassName="com.hardydou.learn.agent.PreAgent"
sourceCompatibility = 1.8

打包

1
agent.jar

运行

为主函数添加jvm参数

1
-javaagent: 路径/preAgent.jar=params 

输出

1
2
permain = params

主程序之后的代理程序

启动前的案例应用还是有点憋屈,至少需要重启一次应用。然而一个异常可能需要程序运行出发某一些条件后才会出现异常。这时就充满了不确定性。主程序之后的代理程序就比较爽了。

编写Agent

1
2
3
4
5
6
7
8
9
//方法名不可以变
   public static void agentmain(String args, Instrumentation inst) {
System.out.println("PostAgent.agentmain args=" + args);
Class<?>[] clazzes = inst.getAllLoadedClasses();
for (Class clazz : clazzes) {
System.out.println(clazz.getName());
}
System.out.println("PostAgent.agentmain end…");
}

修改MAINFEST.MF文件

添加

1
Agent-Class: com.hardydou.agent.PostAgent

打包

1
agent.jar

运行

1
2
3
//可以通过jps获取
VirtualMachine target = VirtualMachine.attach("目标VM线程ID");
target.loadAgent("……/out/artifacts/agent/agent.jar");

输出

你会发现在Agent的线程里面不会输出任何东西,有问题?别着急,内容会在Target线程输出。

进阶

ClassFileTransformer

在类的字节码载入jvm前会调用ClassFileTransformer的transform方法,从而实现修改原类方法的功能。

衍生

JProfiler

JProfiler 是一个商业的主要用于检查和跟踪系统(限于Java开发的)的性能的工具。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。

Jvisualvm

VisualVM 是Netbeans的profile子项目,已在JDK6.0 update 7 中自带(java启动时不需要特定参数,监控工具在bin/jvisualvm.exe),能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)。

BTrace


原理图
BTrace

Arthas(推荐)

遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
Arthas
Arthas文档