一、查看class文件结构
javap -v xxx,注意一定要在xxx.class文件所在目录下
java重载是编译器来选择的,如下:
Code:
stack=2, locals=5, args_size=1
0: new #16 // class com/example/demo/spi/Cat
3: dup
4: invokespecial #18 // Method com/example/demo/spi/Cat."<init>":()V
7: astore_1
8: new #19 // class com/example/demo/spi/Dog
11: dup
12: invokespecial #21 // Method com/example/demo/spi/Dog."<init>":()V
15: astore_2
16: new #1 // class com/example/demo/spi/ShadowTest
19: dup
20: invokespecial #22 // Method "<init>":()V
23: astore_3
24: aload_3
25: aload_1
26: invokevirtual #23 // Method sayHello:(Lcom/example/demo/spi/IShot;)V
29: aload_3
30: aload_2
31: invokevirtual #23 // Method sayHello:(Lcom/example/demo/spi/IShot;)V
34: ldc #27 // String a
36: astore 4
38: aload_3
39: aload 4
41: invokevirtual #29 // Method sayHello:(Ljava/lang/Object;)V
44: aload_3
45: bipush 98
47: invokevirtual #32 // Method sayHello:(C)V
50: aload_3
51: ldc #35 // String c
53: invokevirtual #29 // Method sayHello:(Ljava/lang/Object;)V
56: return
源码code:
public static void main(String... args) {
IShot c = new Cat();
IShot d = new Dog();
ShadowTest shadowTest = new ShadowTest();
shadowTest.sayHello(c);
shadowTest.sayHello(d);
Object cha = "a";
shadowTest.sayHello(cha);
shadowTest.sayHello('b');
shadowTest.sayHello("c");
}
可以看到,shadowTest.sayHello(c)的字节码指令,已经选择了:// Method sayHello:(Lcom/example/demo/spi/IShot;)V 这个重载的方法。🤣
二、查看jvm运行参数
- jps -v 来实现,
- jinfo -flags <pid>。但是jinfo好像在java8有问题。但是我用java13也不行。。。
- ps -ef | grep java
三、查看java代码的汇编指令:
参考:
查看Java的汇编指令
下载macos的java汇编包
上面环境准备好后,使用如下命令:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly xxx (xxx是class文件)
由于汇编内容太大,导致控制台输出被截断。需要使用重定向输出。如下:
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly VolatileTest.class > a
a文件在当前执行命令的路径上,去该目录查看即可看到a文件。如下:
image.png
四、java hsdis 无法打印自己类的方法
使用hsdis打印java源码的汇编,在生成的汇编文件中,总是找不到自己类方法的汇编。
原因:没找到你想要看的方法,说明该方法没有进入JIT编译。没有进入JIT编译,说明该方法没有达到足够的调用次数。
比如:
public class VolatileTest {
private static volatile int a = 0;
public static void main(String[] args){
test123();
}
private static void test123(){
a += 1;
}
}
上面的main方法在执行后,使用-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly是无法打印出test123方法的汇编的。因为没有达到足够的调用次数。改为如下即可:
public class VolatileTest {
private static volatile int a = 0;
public static void main(String[] args){
for(int i=0; i<50000; i++){
test123();
}
}
private static void test123(){
a += 1;
}
}
生成的汇编如下,由于文件很大,采用搜索指定方法查看:
image.png
当然这只是截取了片段。
总结:-XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly打印的是VolatileTest类执行时所有的JIT编译后的代码,肯定不止VolatileTest类里面的方法。相反VolatileTest类如果达不到JIT编译条件,你还看不到。。。大坑,网上很多资料都没说,导致用第一个版本的测试类,死活找不到想要看的方法。。。
网友评论