添加描述
JavaAgent技术基于JVM工具接口(JVMTI),通过字节码插桩实现其功能,字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。
JavaAgent技术是一种在Java虚拟机(JVM)上运行的代理程序,它允许开发者在运行时修改Java字节码,从而实现对Java应用程序的动态增强和监控。
Java Agent:是一个特殊的Java类,它实现了premain方法或agentmain方法;最终解耦了对代码的增强处理。
添加描述
一般JavaAgent技术通过两种方式启动:加载时启动和运行时启动。
MANIFEST.MF:Java Agent的JAR文件必须包含一个MANIFEST.MF文件,其中指定了Premain-Class或Agent-Class属性。
@Slf4j
public class JvmMonitorPreMainAgent {
public static void premain(String agentArgs, Instrumentation inst) {
log.info("this is my agent - premain:{}", agentArgs);
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
@SneakyThrows
public void run() {
JvmStack.printMemoryInfo();
JvmStack.printGCInfo();
log.info("===================================================================================================");
}
}, 0, 5000, TimeUnit.MILLISECONDS);
}
}
打印JVM信息工具类
@Slf4j
public class JvmStack {
private static final long MB = 1048576L;
public static void printMemoryInfo() {
MemoryMXBean memory = ManagementFactory.getMemoryMXBean();
MemoryUsage headMemory = memory.getHeapMemoryUsage();
String info = String.format("init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
headMemory.getInit() / MB + "MB",
headMemory.getMax() / MB + "MB", headMemory.getUsed() / MB + "MB",
headMemory.getCommitted() / MB + "MB",
headMemory.getUsed() * 100 / headMemory.getCommitted() + "%"
);
log.info("printMemoryInfo = {}", info);
MemoryUsage nonheadMemory = memory.getNonHeapMemoryUsage();
info = String.format("init: %s\t max: %s\t used: %s\t committed: %s\t use rate: %s\n",
nonheadMemory.getInit() / MB + "MB",
nonheadMemory.getMax() / MB + "MB", nonheadMemory.getUsed() / MB + "MB",
nonheadMemory.getCommitted() / MB + "MB",
nonheadMemory.getUsed() * 100 / nonheadMemory.getCommitted() + "%"
);
log.info("nonheadMemory = {}", info);
}
public static void printGCInfo() {
List<GarbageCollectorMXBean> garbages = ManagementFactory.getGarbageCollectorMXBeans();
for (GarbageCollectorMXBean garbage : garbages) {
String info = String.format("name: %s\t count:%s\t took:%s\t pool name:%s",
garbage.getName(),
garbage.getCollectionCount(),
garbage.getCollectionTime(),
Arrays.deepToString(garbage.getMemoryPoolNames()));
log.info("printGCInfo = {}", info);
}
}
}
Manifest-Version: 1.0
Premain-Class: org.example.agent.JvmMonitorPreMainAgent
Can-Retransform-Classes: true
Can-Redefine-Classes: true
Created-By: Apache Maven
Built-By: bryant
-XX:+PrintGCDetails -Xmx300m -Xms100m -Xmn50m \
-javaagent:/Users/bryantmo/Downloads/code/springcloud_test/agent/target/agent.jar=youCanDoIt \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/Users/bryantmo/Desktop \
-XX:ErrorFile=/Users/bryantmo/Desktop/error.log
-javaagent:配置了agent的jar包位置,并通过分隔符传入一个参数值"youCanDoIt"
2024-12-22 11:25:59.300 INFO [users,,,] 1607 --- [pool-1-thread-1] org.example.agent.util.JvmStack : printMemoryInfo = init: 104MB max: 304MB used: 42MB committed: 104MB use rate: 40%
2024-12-22 11:25:59.300 INFO [users,,,] 1607 --- [pool-1-thread-1] org.example.agent.util.JvmStack : nonheadMemory = init: 7MB max: 0MB used: 75MB committed: 78MB use rate: 95%
2024-12-22 11:25:59.301 INFO [users,,,] 1607 --- [pool-1-thread-1] org.example.agent.util.JvmStack : printGCInfo = name: G1 Young Generation count:12 took:35 pool name:[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
2024-12-22 11:25:59.301 INFO [users,,,] 1607 --- [pool-1-thread-1] org.example.agent.util.JvmStack : printGCInfo = name: G1 Old Generation count:0 took:0 pool name:[G1 Eden Space, G1 Survivor Space, G1 Old Gen]
2024-12-22 11:25:59.301 INFO [users,,,] 1607 --- [pool-1-thread-1] o.example.agent.JvmMonitorPreMainAgent : ===================================================================================================
2024-12-22 11:25:59.351 INFO [users,,,] 1607 --- [ main] o.s.b.a.e.web.ServletEndpointRegistrar : Registered '/actuator/hystrix.stream' to hystrix.stream-actuator-endpoint
[5.300s][info ][gc,start ] GC(14) Pause Young (Normal) (G1 Evacuation Pause)
[5.300s][info ][gc,task ] GC(14) Using 8 workers of 8 for evacuation
[5.302s][info ][gc,phases ] GC(14) Pre Evacuate Collection Set: 0.0ms
[5.302s][info ][gc,phases ] GC(14) Evacuate Collection Set: 2.1ms
[5.302s][info ][gc,phases ] GC(14) Post Evacuate Collection Set: 0.5ms
[5.302s][info ][gc,phases ] GC(14) Other: 0.1ms
[5.302s][info ][gc,heap ] GC(14) Eden regions: 45->0(45)
[5.302s][info ][gc,heap ] GC(14) Survivor regions: 5->5(7)
[5.302s][info ][gc,heap ] GC(14) Old regions: 24->26
[5.302s][info ][gc,heap ] GC(14) Archive regions: 0->0
[5.302s][info ][gc,heap ] GC(14) Humongous regions: 0->0
[5.302s][info ][gc,metaspace ] GC(14) Metaspace: 54544K(56064K)->54544K(56064K) NonClass: 47889K(48896K)->47889K(48896K) Class: 6654K(7168K)->6654K(7168K)
[5.302s][info ][gc ] GC(14) Pause Young (Normal) (G1 Evacuation Pause) 73M->29M(104M) 2.795ms
[5.302s][info ][gc,cpu ] GC(14) User=0.02s Sys=0.00s Real=0.00s
[5.444s][info ][gc,start ] GC(15) Pause Young (Concurrent Start) (Metadata GC Threshold)
[5.444s][info ][gc,task ] GC(15) Using 8 workers of 8 for evacuation
[5.448s][info ][gc,phases ] GC(15) Pre Evacuate Collection Set: 0.0ms
[5.448s][info ][gc,phases ] GC(15) Evacuate Collection Set: 3.0ms
[5.448s][info ][gc,phases ] GC(15) Post Evacuate Collection Set: 0.9ms
[5.448s][info ][gc,phases ] GC(15) Other: 0.1ms
[5.448s][info ][gc,heap ] GC(15) Eden regions: 40->0(45)
[5.448s][info ][gc,heap ] GC(15) Survivor regions: 5->5(7)
[5.448s][info ][gc,heap ] GC(15) Old regions: 26->28
[5.448s][info ][gc,heap ] GC(15) Archive regions: 0->0
[5.448s][info ][gc,heap ] GC(15) Humongous regions: 0->0
[5.448s][info ][gc,metaspace ] GC(15) Metaspace: 58802K(60160K)->58802K(60160K) NonClass: 51577K(52352K)->51577K(52352K) Class: 7225K(7808K)->7225K(7808K)
[5.448s][info ][gc ] GC(15) Pause Young (Concurrent Start) (Metadata GC Threshold) 68M->31M(104M) 3.947ms
[5.448s][info ][gc,cpu ] GC(15) User=0.02s Sys=0.00s Real=0.01s
[5.448s][info ][gc ] GC(16) Concurrent Cycle
[5.448s][info ][gc,marking ] GC(16) Concurrent Clear Claimed Marks
[5.448s][info ][gc,marking ] GC(16) Concurrent Clear Claimed Marks 0.060ms
[5.448s][info ][gc,marking ] GC(16) Concurrent Scan Root Regions
[5.450s][info ][gc,marking ] GC(16) Concurrent Scan Root Regions 1.617ms
[5.450s][info ][gc,marking ] GC(16) Concurrent Mark (5.450s)
[5.450s][info ][gc,marking ] GC(16) Concurrent Mark From Roots
[5.450s][info ][gc,task ] GC(16) Using 2 workers of 2 for marking
[5.462s][info ][gc,marking ] GC(16) Concurrent Mark From Roots 11.884ms
[5.462s][info ][gc,marking ] GC(16) Concurrent Preclean
[5.462s][info ][gc,marking ] GC(16) Concurrent Preclean 0.064ms
[5.462s][info ][gc,marking ] GC(16) Concurrent Mark (5.450s, 5.462s) 11.962ms
[5.462s][info ][gc,start ] GC(16) Pause Remark
[5.465s][info ][gc,stringtable] GC(16) Cleaned string and symbol table, strings: 29316 processed, 19 removed, symbols: 182551 processed, 580 removed
[5.466s][info ][gc ] GC(16) Pause Remark 35M->35M(104M) 3.572ms
[5.466s][info ][gc,cpu ] GC(16) User=0.02s Sys=0.00s Real=0.00s
[5.466s][info ][gc,marking ] GC(16) Concurrent Rebuild Remembered Sets
[5.474s][info ][gc,marking ] GC(16) Concurrent Rebuild Remembered Sets 8.430ms
[5.474s][info ][gc,start ] GC(16) Pause Cleanup
[5.474s][info ][gc ] GC(16) Pause Cleanup 36M->36M(104M) 0.047ms
[5.474s][info ][gc,cpu ] GC(16) User=0.00s Sys=0.00s Real=0.00s
[5.474s][info ][gc,marking ] GC(16) Concurrent Cleanup for Next Mark
[5.474s][info ][gc,marking ] GC(16) Concurrent Cleanup for Next Mark 0.094ms
[5.474s][info ][gc ] GC(16) Concurrent Cycle 26.032ms
2024-12-22 11:25:59.654 INFO [users,,,] 1607 --- [ main] org.redisson.Version : Redisson 3.14.0
[5.587s][info ][gc,start ] GC(17) Pause Young (Normal) (G1 Evacuation Pause)
[5.587s][info ][gc,task ] GC(17) Using 8 workers of 8 for evacuation
[5.591s][info ][gc,phases ] GC(17) Pre Evacuate Collection Set: 0.0ms
[5.591s][info ][gc,phases ] GC(17) Evacuate Collection Set: 3.0ms
[5.591s][info ][gc,phases ] GC(17) Post Evacuate Collection Set: 0.6ms
[5.591s][info ][gc,phases ] GC(17) Other: 0.1ms
[5.591s][info ][gc,heap ] GC(17) Eden regions: 45->0(43)
[5.591s][info ][gc,heap ] GC(17) Survivor regions: 5->7(7)
[5.591s][info ][gc,heap ] GC(17) Old regions: 28->29
[5.591s][info ][gc,heap ] GC(17) Archive regions: 0->0
[5.591s][info ][gc,heap ] GC(17) Humongous regions: 0->0
[5.591s][info ][gc,metaspace ] GC(17) Metaspace: 61046K(62592K)->61046K(62592K) NonClass: 53574K(54528K)->53574K(54528K) Class: 7472K(8064K)->7472K(8064K)
[5.591s][info ][gc ] GC(17) Pause Young (Normal) (G1 Evacuation Pause) 76M->35M(104M) 3.693ms
[5.591s][info ][gc,cpu ] GC(17) User=0.03s Sys=0.00s Real=0.00s
@Slf4j
public class JvmMonitorAgentMainAgent {
public static void agentmain(String agentArgs, Instrumentation inst){
log.info("this is my agent - agentmain:{}", inst);
//针对运行期的类进行增强
inst.addTransformer(new ClassTransformer(),true);
//agentmain运行时 由于堆里已经存在Class文件,所以新添加Transformer后
// 还要再调用一个 inst.retransformClasses(clazz); 方法来更新Class文件
for (Class clazz:inst.getAllLoadedClasses()) {
log.info("findout class, name = {}", clazz.getName());
// if (clazz.getName().contains("com.bryant.agent.TestAgentBean")){
// try {
// instrumentation.retransformClasses(clazz);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
}
}
}
Manifest-Version: 1.0
Premain-Class: org.example.agent.JvmMonitorPreMainAgent
Agent-Class: org.example.agent.JvmMonitorAgentMainAgent
Can-Retransform-Classes: true
Can-Redefine-Classes: true
Created-By: Apache Maven
Built-By: bryant
1571 EurekaApplication
1492 RemoteMavenServer36
1606 Launcher
1607 UserServer
1576 ConfigServer
1498 RemoteMavenServer36
1631 Jps
我们的启动app是UserServer,对应的PID是1607。
public class Main {
/**
* 这个main方法可以多次被执行,在字节码层面,完成对JVM的多次热修改部署
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// 获取当前 JVM 进程的 PID
String pid = "12460";
// String pid = Long.toString(ProcessHandle.current().pid());
// 加载代理
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgent("/Users/bryantmo/Downloads/code/springcloud_test/agent/target/agent.jar");
vm.detach();
}
}
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForByte
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForShort
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForInteger
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForLong
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForFloat
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForDouble
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForBigInteger
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveOrZeroValidatorForBigDecimal
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = javax.validation.constraints.PositiveOrZero
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.springframework.boot.system.ApplicationPid
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveValidatorForNumber
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.springframework.boot.logging.LoggingSystemProperties
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveValidatorForByte
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = org.hibernate.validator.internal.constraintvalidators.bv.number.sign.PositiveValidatorForShort
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = [Lorg.springframework.boot.ansi.AnsiColor;
2024-12-22 11:30:32.620 INFO [users,,,] 1607 --- [Attach Listener] o.e.agent.JvmMonitorAgentMainAgent : findout class, name = [Lorg.springframework.boot.ansi.AnsiElement;
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。