深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
28026 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

33 | Java Agent与字节码注入

郑雨迪 2018-10-05
关于 Java agent,大家可能都听过大名鼎鼎的premain方法。顾名思义,这个方法指的就是在main方法之前执行的方法。
package org.example;
public class MyAgent {
public static void premain(String args) {
System.out.println("premain");
}
}
我在上面这段代码中定义了一个premain方法。这里需要注意的是,Java 虚拟机所能识别的premain方法接收的是字符串类型的参数,而并非类似于main方法的字符串数组。
为了能够以 Java agent 的方式运行该premain方法,我们需要将其打包成 jar 包,并在其中的 MANIFEST.MF 配置文件中,指定所谓的Premain-class。具体的命令如下所示:
# 注意第一条命令会向manifest.txt文件写入两行数据,其中包括一行空行
$ echo 'Premain-Class: org.example.MyAgent
' > manifest.txt
$ jar cvmf manifest.txt myagent.jar org/
$ java -javaagent:myagent.jar HelloWorld
premain
Hello, World
除了在命令行中指定 Java agent 之外,我们还可以通过 Attach API 远程加载。具体用法如下面的代码所示:
import java.io.IOException;
import com.sun.tools.attach.*;
public class AttachTest {
public static void main(String[] args)
throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException {
if (args.length <= 1) {
System.out.println("Usage: java AttachTest <PID> /PATH/TO/AGENT.jar");
return;
}
VirtualMachine vm = VirtualMachine.attach(args[0]);
vm.loadAgent(args[1]);
}
}
使用 Attach API 远程加载的 Java agent 不会再先于main方法执行,这取决于另一虚拟机调用 Attach API 的时机。并且,它运行的也不再是premain方法,而是名为agentmain的方法。
public class MyAgent {
public static void agentmain(String args) {
System.out.println("agentmain");
}
}
相应的,我们需要更新 jar 包中的 manifest 文件,使其包含Agent-Class的配置,例如Agent-Class: org.example.MyAgent
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(9)

  • godtrue
    阅过留痕

    1:Java agent 是啥玩意?
          这个概念老师没有详细讲解,我的理解是Java语言的一个特性,这个特性能够实现Java字节码的注入

    2:Java字节码的注入有什么用处呢?
    在平时编程几乎没有使用到这方面的功能,应该是在一些框架的设计的时候才使用吧!比如:专栏中提到的面相切面编程。

    3:Java agent 本质上是通过 c agent 来实现的,那 c agent 本质上是怎么实现的呢?
    C agent是一个事件驱动的工具实现接口,通常我们会在 C agent 加载后的入口方案 Agent_OnLoad处注册各个事件的钩子方法。当Java虚拟机触发了这些事件时,便会调用对应的钩子方法

    4:留个话头
          写代码实现某些功能,我的理解有三个时间段
          第一个:源码阶段,最常用的,也是编程的主要活动时间
          第二个:字节码阶段,有些功能可能会在加载字节码时修改或者添加某些字节码,某些框架做的事情
          第三个:运行阶段,某些工具,在程序运行时修改代码,实现运行时功能分支的控制
    2018-10-13
    6
  • 小美
    用attach的方式注入字节码的时候遇到了99线升高的性能问题,看一些资料说 class redefinition 的时候会阻塞线程。请问能详细讲下吗?

    作者回复: 你是在做redefine时出问题,还是没触发时便已出问题?

    class redefinition需要爬每个线程的Java栈,检查有没有用到被redefine的类的方法,因此会stop-the-world。另外,redefine后,JIT’ed代码会被抛弃,重新解释执行

    2018-11-19
    4
  • feng
    第一个实验做的不严谨,第一,木有定义HelloWord类,第二,没有执行编译操作,不知道是有意为之,还是不小心把步骤漏掉了
    2018-10-07
    3
  • Scott
    我看到了jvmti可以回调异常事件,但是java.lang.instrument包下没有处理这个事件的,只能在load时回调,处理异常究竟是怎么做的?

    作者回复: Instrumentation包并没有所有JVMTI功能

    2018-10-06
    1
  • Scott
    出方法时需要注入的字节码除了返回,还有几种情况,如果没有catch块,就拦截throw,如果有,但是catch块里面可能有很多层,只是遍历inst应该是不可以的

    作者回复: 其实不用管有没有catch块,有没有throw,直接给所有代码罩一个catch any的异常处理就行了

    2018-10-06
    1
  • 随心而至
    把老师给的程序都跑了一篇,发现想要彻底搞懂,还需要多学习,C/C++的知识不能丢了,因为HotSpot JVM 的源码基本上都是用它来实现的。
    不过跑了一下代码,最起码可以表面上搞懂了像Lombok,AOP这些都是如何实现的。
    2019-11-01
  • 一缕阳光
    实习的时候有幸做过一个利用Instrumentation实现自动打点和性能监控的项目。受益匪浅啊 哈哈哈哈 ,不得不说里面坑还是挺多的
    2019-07-07
  • 奇奇
    ASM7 GETSTATIC这些常量是哪里来的?
    2019-04-29
  • feng
    还有个问题想请教下,每次启动的时候都会打印如下信息,objc[2614]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/bin/java (0x102f6f4c0) and /Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk/Contents/Home/jre/lib/libinstrument.dylib (0x104f384e0). One of the two will be used. Which one is undefined.

    请问怎么可以消除,谢谢
    2018-10-07
收起评论
9
返回
顶部