挺有意思的  转载记录下

转载自 https://www.cnblogs.com/f1194361820/p/8524666.html    原作者: 房继诺

JVM 指令

在java程序开发过程中,没有源码是很常见的事,我们可以通过IDE(Eclipse需要配置jad.exe、IDEA)自动的将class文件反编 译为java文件。或者我们借助于其他工具(jd-gui, luyten)来直接的对整个jar包进行反编译。反编译工具是如何做到代码反编译的呢?如果是在生产环境下帮助用户解决问题时,是没有这些工具的,该怎 么办呢?

在开发apm,jprofiler这样的工具时,spring团队在实现aop (例如interceptor),通常都会通过字节码 技术对已有代码进行改造,以达到对代码进行监控,改造工作。那么又是如何将字节码指令嵌入的呢?

要想了解这些东西,不学习class文件如何看,不了解相关字节码指令是很难解决上面的问题的。

1、Demo

在了解class文件之前,先来看一个例子:这是一个真实的需求。不同的机器时间没有使用NTP服务进行时间同步。在这样的一个环境下,各个机器的数据都 以入库(如果的数据是机器自身的时间),现在要查看某个机器当前时间的数据,或者最近20分钟的数据。为了解决该问题,做了一个机器时间计算工具:

实现的源码如下:

public class RelativeTime
{
private String machineId;
private long delta; public RelativeTime() {
} public RelativeTime(final String machineId, final long time) {
this.machineId = machineId;
final long now = System.currentTimeMillis();
this.delta = now - time;
} public String getMachineId() {
return this.machineId;
} public void setMachineId(final String machineId) {
this.machineId = machineId;
} public long getDelta() {
return this.delta;
} public void setDelta(final long delta) {
this.delta = delta;
}
}
import java.util.concurrent.*;

public class RelativeTimeManager
{
private final ConcurrentHashMap<String, RelativeTime> cache; public RelativeTimeManager() {
this.cache = new ConcurrentHashMap<String, RelativeTime>();
} public void add(final String machineId, final long machineTime) {
if (machineId != null) {
final RelativeTime t = new RelativeTime(machineId, machineTime);
this.add(t);
}
} public void add(final RelativeTime time) {
if (time != null) {
this.cache.put(time.getMachineId(), time);
}
} public void addIfAbsent(final String machineId, final long machineTime) {
if (machineId != null && machineTime > 0L) {
final RelativeTime t = new RelativeTime(machineId, machineTime);
this.addIfAbsent(t);
}
} public void addIfAbsent(final RelativeTime time) {
this.cache.putIfAbsent(time.getMachineId(), time);
} public void remove(final String machineId) {
if (machineId != null) {
this.cache.remove(machineId);
}
} public boolean hasMachine(final String machineId) {
return machineId != null && this.cache.get(machineId) != null;
} public long getDeltaTime(final String machineId) {
return this.cache.get(machineId).getDelta();
} public long getMachineCurrentTime(final String machineId) {
return this.getMachineRelativeTime(machineId, System.currentTimeMillis());
} public long getMachineRelativeTime(final String machineId, final long time) {
if (this.hasMachine(machineId)) {
final long delta = this.getDeltaTime(machineId);
return time - delta;
}
return time;
}
}

先来解决上面提出的第一个问题,没有反编译工具的情况下如何查看java类:

在java_home/bin目录下,有这样一个工具:javap,使用它即可查看class文件内容。

对上述两个类分别执行 javap -l -v -p RelativeTime.class (javap -l -v -p RelativeTimeManager.class) 命令后如下:

RelativeTime:

Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTime.class
Last modified 2017-11-10; size 1005 bytes
MD5 checksum eff96db3a12a575b2a4ebc1272b896e4
Compiled from "RelativeTime.java"
public class com.bes.webgate.common.clock.RelativeTime
SourceFile: "RelativeTime.java"
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#31 // java/lang/Object."<init>":()V
#2 = Fieldref #5.#32 // com/bes/webgate/common/clock/RelativeTime.machineId:Ljava/lang/String;
#3 = Methodref #33.#34 // java/lang/System.currentTimeMillis:()J
#4 = Fieldref #5.#35 // com/bes/webgate/common/clock/RelativeTime.delta:J
#5 = Class #36 // com/bes/webgate/common/clock/RelativeTime
#6 = Class #37 // java/lang/Object
#7 = Utf8 machineId
#8 = Utf8 Ljava/lang/String;
#9 = Utf8 delta
#10 = Utf8 J
#11 = Utf8 <init>
#12 = Utf8 ()V
#13 = Utf8 Code
#14 = Utf8 LineNumberTable
#15 = Utf8 LocalVariableTable
#16 = Utf8 this
#17 = Utf8 Lcom/bes/webgate/common/clock/RelativeTime;
#18 = Utf8 (Ljava/lang/String;J)V
#19 = Utf8 time
#20 = Utf8 now
#21 = Utf8 getMachineId
#22 = Utf8 ()Ljava/lang/String;
#23 = Utf8 setMachineId
#24 = Utf8 (Ljava/lang/String;)V
#25 = Utf8 getDelta
#26 = Utf8 ()J
#27 = Utf8 setDelta
#28 = Utf8 (J)V
#29 = Utf8 SourceFile
#30 = Utf8 RelativeTime.java
#31 = NameAndType #11:#12 // "<init>":()V
#32 = NameAndType #7:#8 // machineId:Ljava/lang/String;
#33 = Class #38 // java/lang/System
#34 = NameAndType #39:#26 // currentTimeMillis:()J
#35 = NameAndType #9:#10 // delta:J
#36 = Utf8 com/bes/webgate/common/clock/RelativeTime
#37 = Utf8 java/lang/Object
#38 = Utf8 java/lang/System
#39 = Utf8 currentTimeMillis
{
private java.lang.String machineId;
flags: ACC_PRIVATE private long delta;
flags: ACC_PRIVATE public com.bes.webgate.common.clock.RelativeTime();
flags: ACC_PUBLIC
LineNumberTable:
line 20: 0
line 22: 4
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime;
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 20: 0
line 22: 4
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public com.bes.webgate.common.clock.RelativeTime(java.lang.String, long);
flags: ACC_PUBLIC
LineNumberTable:
line 24: 0
line 25: 4
line 26: 9
line 27: 14
line 28: 22
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 23 1 machineId Ljava/lang/String;
0 23 2 time J
14 9 4 now J
Code:
stack=5, locals=6, args_size=3
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_1
6: putfield #2 // Field machineId:Ljava/lang/String;
9: invokestatic #3 // Method java/lang/System.currentTimeMillis:()J
12: lstore 4
14: aload_0
15: lload 4
17: lload_2
18: lsub
19: putfield #4 // Field delta:J
22: return
LineNumberTable:
line 24: 0
line 25: 4
line 26: 9
line 27: 14
line 28: 22
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 23 1 machineId Ljava/lang/String;
0 23 2 time J
14 9 4 now J public java.lang.String getMachineId();
flags: ACC_PUBLIC
LineNumberTable:
line 31: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime;
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field machineId:Ljava/lang/String;
4: areturn
LineNumberTable:
line 31: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public void setMachineId(java.lang.String);
flags: ACC_PUBLIC
LineNumberTable:
line 35: 0
line 36: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 6 1 machineId Ljava/lang/String;
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #2 // Field machineId:Ljava/lang/String;
5: return
LineNumberTable:
line 35: 0
line 36: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 6 1 machineId Ljava/lang/String; public long getDelta();
flags: ACC_PUBLIC
LineNumberTable:
line 39: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime;
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #4 // Field delta:J
4: lreturn
LineNumberTable:
line 39: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/bes/webgate/common/clock/RelativeTime; public void setDelta(long);
flags: ACC_PUBLIC
LineNumberTable:
line 43: 0
line 44: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 6 1 delta J
Code:
stack=3, locals=3, args_size=2
0: aload_0
1: lload_1
2: putfield #4 // Field delta:J
5: return
LineNumberTable:
line 43: 0
line 44: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/bes/webgate/common/clock/RelativeTime;
0 6 1 delta J
}

RelativeTimeManager:

Classfile /C:/Users/User/Desktop/webgate-commons/com/bes/webgate/common/clock/RelativeTimeManager.class
Last modified 2017-11-10; size 2352 bytes
MD5 checksum 3475ce705b7622e212b5630a59413264
Compiled from "RelativeTimeManager.java"
public class com.bes.webgate.common.clock.RelativeTimeManager
SourceFile: "RelativeTimeManager.java"
minor version: 0
major version: 50
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #20.#56 // java/lang/Object."<init>":()V
#2 = Class #57 // java/util/concurrent/ConcurrentHashMap
#3 = Methodref #2.#56 // java/util/concurrent/ConcurrentHashMap."<init>":()V
#4 = Fieldref #19.#58 // com/bes/webgate/common/clock/RelativeTimeManager.cache:Ljava/util/concurrent/ConcurrentHashMap;
#5 = Class #59 // com/bes/webgate/common/clock/RelativeTime
#6 = Methodref #5.#60 // com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
#7 = Methodref #19.#61 // com/bes/webgate/common/clock/RelativeTimeManager.add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
#8 = Methodref #5.#62 // com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
#9 = Methodref #2.#63 // java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#10 = Methodref #19.#64 // com/bes/webgate/common/clock/RelativeTimeManager.addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
#11 = Methodref #2.#65 // java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#12 = Methodref #2.#66 // java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object;
#13 = Methodref #2.#67 // java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
#14 = Methodref #5.#68 // com/bes/webgate/common/clock/RelativeTime.getDelta:()J
#15 = Methodref #69.#70 // java/lang/System.currentTimeMillis:()J
#16 = Methodref #19.#71 // com/bes/webgate/common/clock/RelativeTimeManager.getMachineRelativeTime:(Ljava/lang/String;J)J
#17 = Methodref #19.#72 // com/bes/webgate/common/clock/RelativeTimeManager.hasMachine:(Ljava/lang/String;)Z
#18 = Methodref #19.#73 // com/bes/webgate/common/clock/RelativeTimeManager.getDeltaTime:(Ljava/lang/String;)J
#19 = Class #74 // com/bes/webgate/common/clock/RelativeTimeManager
#20 = Class #75 // java/lang/Object
#21 = Utf8 cache
#22 = Utf8 Ljava/util/concurrent/ConcurrentHashMap;
#23 = Utf8 Signature
#24 = Utf8 Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>;
#25 = Utf8 <init>
#26 = Utf8 ()V
#27 = Utf8 Code
#28 = Utf8 LineNumberTable
#29 = Utf8 LocalVariableTable
#30 = Utf8 this
#31 = Utf8 Lcom/bes/webgate/common/clock/RelativeTimeManager;
#32 = Utf8 add
#33 = Utf8 (Ljava/lang/String;J)V
#34 = Utf8 t
#35 = Utf8 Lcom/bes/webgate/common/clock/RelativeTime;
#36 = Utf8 machineId
#37 = Utf8 Ljava/lang/String;
#38 = Utf8 machineTime
#39 = Utf8 J
#40 = Utf8 StackMapTable
#41 = Utf8 (Lcom/bes/webgate/common/clock/RelativeTime;)V
#42 = Utf8 time
#43 = Utf8 addIfAbsent
#44 = Utf8 remove
#45 = Utf8 (Ljava/lang/String;)V
#46 = Utf8 hasMachine
#47 = Utf8 (Ljava/lang/String;)Z
#48 = Utf8 getDeltaTime
#49 = Utf8 (Ljava/lang/String;)J
#50 = Utf8 getMachineCurrentTime
#51 = Utf8 getMachineRelativeTime
#52 = Utf8 (Ljava/lang/String;J)J
#53 = Utf8 delta
#54 = Utf8 SourceFile
#55 = Utf8 RelativeTimeManager.java
#56 = NameAndType #25:#26 // "<init>":()V
#57 = Utf8 java/util/concurrent/ConcurrentHashMap
#58 = NameAndType #21:#22 // cache:Ljava/util/concurrent/ConcurrentHashMap;
#59 = Utf8 com/bes/webgate/common/clock/RelativeTime
#60 = NameAndType #25:#33 // "<init>":(Ljava/lang/String;J)V
#61 = NameAndType #32:#41 // add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
#62 = NameAndType #76:#77 // getMachineId:()Ljava/lang/String;
#63 = NameAndType #78:#79 // put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#64 = NameAndType #43:#41 // addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
#65 = NameAndType #80:#79 // putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#66 = NameAndType #44:#81 // remove:(Ljava/lang/Object;)Ljava/lang/Object;
#67 = NameAndType #82:#81 // get:(Ljava/lang/Object;)Ljava/lang/Object;
#68 = NameAndType #83:#84 // getDelta:()J
#69 = Class #85 // java/lang/System
#70 = NameAndType #86:#84 // currentTimeMillis:()J
#71 = NameAndType #51:#52 // getMachineRelativeTime:(Ljava/lang/String;J)J
#72 = NameAndType #46:#47 // hasMachine:(Ljava/lang/String;)Z
#73 = NameAndType #48:#49 // getDeltaTime:(Ljava/lang/String;)J
#74 = Utf8 com/bes/webgate/common/clock/RelativeTimeManager
#75 = Utf8 java/lang/Object
#76 = Utf8 getMachineId
#77 = Utf8 ()Ljava/lang/String;
#78 = Utf8 put
#79 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#80 = Utf8 putIfAbsent
#81 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
#82 = Utf8 get
#83 = Utf8 getDelta
#84 = Utf8 ()J
#85 = Utf8 java/lang/System
#86 = Utf8 currentTimeMillis
{
private final java.util.concurrent.ConcurrentHashMap<java.lang.String, com.bes.webgate.common.clock.RelativeTime> cache;
flags: ACC_PRIVATE, ACC_FINAL
Signature: #24 // Ljava/util/concurrent/ConcurrentHashMap<Ljava/lang/String;Lcom/bes/webgate/common/clock/RelativeTime;>; public com.bes.webgate.common.clock.RelativeTimeManager();
flags: ACC_PUBLIC
LineNumberTable:
line 22: 0
line 20: 4
line 24: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #2 // class java/util/concurrent/ConcurrentHashMap
8: dup
9: invokespecial #3 // Method java/util/concurrent/ConcurrentHashMap."<init>":()V
12: putfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
15: return
LineNumberTable:
line 22: 0
line 20: 4
line 24: 15
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager; public void add(java.lang.String, long);
flags: ACC_PUBLIC
LineNumberTable:
line 27: 0
line 28: 4
line 29: 15
line 31: 21
LocalVariableTable:
Start Length Slot Name Signature
15 6 4 t Lcom/bes/webgate/common/clock/RelativeTime;
0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 22 1 machineId Ljava/lang/String;
0 22 2 machineTime J
Code:
stack=5, locals=5, args_size=3
0: aload_1
1: ifnull 21
4: new #5 // class com/bes/webgate/common/clock/RelativeTime
7: dup
8: aload_1
9: lload_2
10: invokespecial #6 // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
13: astore 4
15: aload_0
16: aload 4
18: invokevirtual #7 // Method add:(Lcom/bes/webgate/common/clock/RelativeTime;)V
21: return
LineNumberTable:
line 27: 0
line 28: 4
line 29: 15
line 31: 21
LocalVariableTable:
Start Length Slot Name Signature
15 6 4 t Lcom/bes/webgate/common/clock/RelativeTime;
0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 22 1 machineId Ljava/lang/String;
0 22 2 machineTime J
StackMapTable: number_of_entries = 1
frame_type = 21 /* same */ public void add(com.bes.webgate.common.clock.RelativeTime);
flags: ACC_PUBLIC
LineNumberTable:
line 34: 0
line 35: 4
line 37: 17
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 18 1 time Lcom/bes/webgate/common/clock/RelativeTime;
Code:
stack=3, locals=2, args_size=2
0: aload_1
1: ifnull 17
4: aload_0
5: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
8: aload_1
9: invokevirtual #8 // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
12: aload_1
13: invokevirtual #9 // Method java/util/concurrent/ConcurrentHashMap.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
16: pop
17: return
LineNumberTable:
line 34: 0
line 35: 4
line 37: 17
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 18 1 time Lcom/bes/webgate/common/clock/RelativeTime;
StackMapTable: number_of_entries = 1
frame_type = 17 /* same */ public void addIfAbsent(java.lang.String, long);
flags: ACC_PUBLIC
LineNumberTable:
line 40: 0
line 41: 10
line 42: 21
line 44: 27
LocalVariableTable:
Start Length Slot Name Signature
21 6 4 t Lcom/bes/webgate/common/clock/RelativeTime;
0 28 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 28 1 machineId Ljava/lang/String;
0 28 2 machineTime J
Code:
stack=5, locals=5, args_size=3
0: aload_1
1: ifnull 27
4: lload_2
5: lconst_0
6: lcmp
7: ifle 27
10: new #5 // class com/bes/webgate/common/clock/RelativeTime
13: dup
14: aload_1
15: lload_2
16: invokespecial #6 // Method com/bes/webgate/common/clock/RelativeTime."<init>":(Ljava/lang/String;J)V
19: astore 4
21: aload_0
22: aload 4
24: invokevirtual #10 // Method addIfAbsent:(Lcom/bes/webgate/common/clock/RelativeTime;)V
27: return
LineNumberTable:
line 40: 0
line 41: 10
line 42: 21
line 44: 27
LocalVariableTable:
Start Length Slot Name Signature
21 6 4 t Lcom/bes/webgate/common/clock/RelativeTime;
0 28 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 28 1 machineId Ljava/lang/String;
0 28 2 machineTime J
StackMapTable: number_of_entries = 1
frame_type = 27 /* same */ public void addIfAbsent(com.bes.webgate.common.clock.RelativeTime);
flags: ACC_PUBLIC
LineNumberTable:
line 47: 0
line 48: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 14 1 time Lcom/bes/webgate/common/clock/RelativeTime;
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
4: aload_1
5: invokevirtual #8 // Method com/bes/webgate/common/clock/RelativeTime.getMachineId:()Ljava/lang/String;
8: aload_1
9: invokevirtual #11 // Method java/util/concurrent/ConcurrentHashMap.putIfAbsent:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
12: pop
13: return
LineNumberTable:
line 47: 0
line 48: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 14 1 time Lcom/bes/webgate/common/clock/RelativeTime; public void remove(java.lang.String);
flags: ACC_PUBLIC
LineNumberTable:
line 51: 0
line 52: 4
line 54: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 14 1 machineId Ljava/lang/String;
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: ifnull 13
4: aload_0
5: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
8: aload_1
9: invokevirtual #12 // Method java/util/concurrent/ConcurrentHashMap.remove:(Ljava/lang/Object;)Ljava/lang/Object;
12: pop
13: return
LineNumberTable:
line 51: 0
line 52: 4
line 54: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 14 1 machineId Ljava/lang/String;
StackMapTable: number_of_entries = 1
frame_type = 13 /* same */ public boolean hasMachine(java.lang.String);
flags: ACC_PUBLIC
LineNumberTable:
line 57: 0
line 58: 4
line 60: 6
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 23 1 machineId Ljava/lang/String;
Code:
stack=2, locals=2, args_size=2
0: aload_1
1: ifnonnull 6
4: iconst_0
5: ireturn
6: aload_0
7: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
10: aload_1
11: invokevirtual #13 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
14: ifnull 21
17: iconst_1
18: goto 22
21: iconst_0
22: ireturn
LineNumberTable:
line 57: 0
line 58: 4
line 60: 6
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 23 1 machineId Ljava/lang/String;
StackMapTable: number_of_entries = 3
frame_type = 6 /* same */
frame_type = 14 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ] public long getDeltaTime(java.lang.String);
flags: ACC_PUBLIC
LineNumberTable:
line 64: 0
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 15 1 machineId Ljava/lang/String;
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: getfield #4 // Field cache:Ljava/util/concurrent/ConcurrentHashMap;
4: aload_1
5: invokevirtual #13 // Method java/util/concurrent/ConcurrentHashMap.get:(Ljava/lang/Object;)Ljava/lang/Object;
8: checkcast #5 // class com/bes/webgate/common/clock/RelativeTime
11: invokevirtual #14 // Method com/bes/webgate/common/clock/RelativeTime.getDelta:()J
14: lreturn
LineNumberTable:
line 64: 0
LocalVariableTable:
Start Length Slot Name Signature
0 15 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 15 1 machineId Ljava/lang/String; public long getMachineCurrentTime(java.lang.String);
flags: ACC_PUBLIC
LineNumberTable:
line 68: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 9 1 machineId Ljava/lang/String;
Code:
stack=4, locals=2, args_size=2
0: aload_0
1: aload_1
2: invokestatic #15 // Method java/lang/System.currentTimeMillis:()J
5: invokevirtual #16 // Method getMachineRelativeTime:(Ljava/lang/String;J)J
8: lreturn
LineNumberTable:
line 68: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 9 1 machineId Ljava/lang/String; public long getMachineRelativeTime(java.lang.String, long);
flags: ACC_PUBLIC
LineNumberTable:
line 72: 0
line 73: 8
line 74: 15
line 76: 20
LocalVariableTable:
Start Length Slot Name Signature
15 5 4 delta J
0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 22 1 machineId Ljava/lang/String;
0 22 2 time J
Code:
stack=4, locals=6, args_size=3
0: aload_0
1: aload_1
2: invokevirtual #17 // Method hasMachine:(Ljava/lang/String;)Z
5: ifeq 20
8: aload_0
9: aload_1
10: invokevirtual #18 // Method getDeltaTime:(Ljava/lang/String;)J
13: lstore 4
15: lload_2
16: lload 4
18: lsub
19: lreturn
20: lload_2
21: lreturn
LineNumberTable:
line 72: 0
line 73: 8
line 74: 15
line 76: 20
LocalVariableTable:
Start Length Slot Name Signature
15 5 4 delta J
0 22 0 this Lcom/bes/webgate/common/clock/RelativeTimeManager;
0 22 1 machineId Ljava/lang/String;
0 22 2 time J
StackMapTable: number_of_entries = 1
frame_type = 20 /* same */ }

2、Class 文件说明

2.1 Class 文件结构

从上面的class文件中,我们就可以看出个大概结构:

从这两个文件的结构中,我们可以轻松的看出一个class文件的结构:

需要注意的是,class文件中,是不会保留代码注释的。如果以非debug模式编译的话,连行号都不会有的。开发过程中的class,都是有行号的,不然都没办法调试了。

2.2 jvm type 、method signature

从上面demo的常量池(Constant pool),可以看到包含了一个类的类型,方法描述,字段描述等。

同时也可以看出类名,方法名,字段名就是和源码一样的,但是字段的类型,方法的类型,和真是的java类型还是有区别的。例如machineId的 java类型java.lang.String,而class文件表示的则是 Ljava/lang/String; long表示为J

看来JVM中是有一套自己的表示方式的:

jvm type signature:

于此同时,我编写了一个java类向jvm type signature转换的工具:

Jvm中也有自己的一套method signature:

(paramTypeSignatures)returnTypeSignature

例如:

有了上面的类型签名的转换工具,想必实现方法前面的转换也就不成问题的了。

2.3 泛型表示

Java类型,方法在jvm都有一套自己的表示方式,Java5中引入的泛型,也自然有一套表示方式的,感兴趣的话,可以自己了解一下。

下面是一些简单的例子:

3、方法说明

了解了class文件结构,类型,方法的表示后,下面就进入重头戏了——查看方法。

3.1 方法结构

从上面的字节码,也能看出一个方法会有一堆的指令组成。每一个方法,大概有这些描述区域:

1) modifier(flags:)

2) LineNumberTable (debug模式编译的class文件才会有,反编译工具反编译处理的代码行号之所以对应,你之所以可以调试代码,就是依赖于此)

3) LocalVariableTable (局部变量表,包含三部分内容: this, 方法的所有参数,方法体中声明的所有局部变量)

4) Code (指令序列,运行是就是按照该序列执行的)

5)StackMapTable(stack map frames table,用于jvm在加载类时,verify阶段对code中指令序列里,在所有的跳转指令处,进行execute method stack frame状态校验。目前可能对这句话不理解,不要急,看了后面的内容,就理解了)

3.1.1 Thread Stack Model

如果你稍有Java开发经验,应该都会调试过代码,或者用jstack打过运行时调用栈,或者是看过exception stack。也就是,在运行时采用stack结构各个方法的调串成一条调用链的。在jvm内部,将运行时stack中的每一个元素(方法调用)看作是一个 execute frame。

每一个execute frame由两部分组成:一个local variables table,一个operand stack。

Local variables table用于放局部变量,this等。

Operand stack 是执行指令时涉及的操作数存放的地方。

3.1.2 指令

Java运行时的最小单位就是指令的执行。一条完整的指令包括两部分,一个是操作码(opcode),一个是操作数(operand)。

例如:IADD a,b ,这条指令是执行a + b, IADD是 opcode, a,b 是operand。

也就是说operand可以理解为opcode的参数。

指令执行时,通常是对三个地方的数据 进行操作1)local variables table, 2) operand stack, 3) constant pool 。

Jvm 提供了很多指令,这些指令大概可以分为两类:

1) 从local variables table 或者 constants pool 将值load到 operand stack,或者反过来将 operand stack 中的值 store 给local variables table。

2) 基于stack 进行操作,例如 IADD, 就从 stack 顶取2个值进行 加法运算后,将结果push到stack。

到此,相信可以大概猜测出运行过程 :执行一个方法时:

1) 构建 execute frame (初始化 local variables table, operand stack)

2) 将execute frame 放到 thread stack。

在构建local variables table时,第一个(也就是index 为0的)是this, 后面紧接的是方法的参数列表。

在执行方法内的指令序列时,遇见 load类指令时,就load数据到operand stack,遇见运算类指令时,就从 operand stack 中取值运行,遇见 store类指令时,就从stack顶取值放到local variables table中。

3.1.3 Stack Map Frames

从Java 6起,引入了使用stack map frames进行字节码校验机制。那么stack map frames到底是怎样一回事呢?

假设你的类,被人篡改了,加入了一些不可描述的指令。通过jvm 的stack map frames检验,是可以帮你查出来问题的。

上面已经说明了operand stack,也了解了指令执行过程,可以说大多数指令,都是要与operand stack打交道的。这个检验就是基于operand stack在执行指令前后的状态来的。

例如:

上面 就是一个stack map。也就是说记录了指令执行前后,operand stack 与 指令的映射关系的表,就是 stack map frames。

一个方法可以很简单,也可以很复杂。对于一个复杂的方法,指令会非常多,那么它的stack map frames 会非常长。如果类加载过程中,要校验这么长的stack map,那性能可想而知。

所以JVM设计者呢,采取了一个折中的方案。只在stack map frames 里只保留跳转指令的状态。至于跳转指令,例如:if,else,try,catch等。

4、字节码工具库

目前常用的字节码操作的工具有:javaassist,asm,bcel

基于asm的库有bytebuddy,cglib

5、指令集

在上面说了,指令主要针对local variables table, operand stack, constants进行操作。如果详细对指令进行归类的话,大概可以归类如下:

1)   Local variables

2)    stack

3)    Constants

4)    Arithmetic and logic

5)    Object,field,method

6)    Array

7)    Jump

8)    Return

JVM 指令讲解的更多相关文章

  1. [转]JVM指令详解(上)

    作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) 本文主要记录一些JVM指令,便于记忆与查阅. 一.未归类系列A 此系列暂未归类. 指令码    助记符      ...

  2. Java并发编程(五)JVM指令重排

    我是不是学了一门假的java...... 引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果.. ...

  3. JVM指令助记符

    以下只是JVM指令助记符,关于JVM指令的详细内容请阅读<JVM指令详解> 变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dlo ...

  4. JVM指令手册

    JVM指令大全 常量入栈指令 指令码 操作码(助记符) 操作数 描述(栈指操作数栈) 0x01 aconst_null null值入栈. 0x02 iconst_m1 -1(int)值入栈. 0x03 ...

  5. (转)JVM原理讲解和调优

    背景:jvm实际调优在面试时候经常被问到,所以有必要认真总结一番. 转自:JVM原理讲解和调优 四.JVM内存调优 首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存 ...

  6. Javap与JVM指令

    一.javap命令简述 javap是jdk自带的反解析工具.它的作用就是根据class字节码文件,反解析出当前类对应的code区(汇编指令).本地变量表.异常表和代码行偏移量映射表.常量池等等信息.当 ...

  7. jvm指令手册查看

    00-JVM指令手册 栈和局部变量操作 将常量压入栈的指令 aconst_null 将null对象引用压入栈 iconst_m1 将int类型常量-1压入栈 iconst_0 将int类型常量0压入栈 ...

  8. 深入JVM(一)JVM指令手册

    本文按照如下思维导图组织 1. 栈和局部变量操作 1.1 将常量压入栈的指令 aconst_null 将null对象引用压入栈iconst_m1 将int类型常量-1压入栈iconst_0 将int类 ...

  9. 2.1 附录--JVM指令手册

    栈和局部变量操作 将常量压入栈的指令 aconst_null 将null对象引用压入栈 iconst_m1 将int类型常量-1压入栈 iconst_0 将int类型常量0压入栈 iconst_1 将 ...

随机推荐

  1. C# 获取当前路径方法(转)

    C# 获取当前路径方法 //获取包含清单的已加载文件的路径或 UNC 位置. public static string sApplicationPath = Assembly.GetExecuting ...

  2. Note:pandas时间序列处理

    Note 1.Time Series #1 from datetime import datetime now=datetime.now() now.year now.month now.day #2 ...

  3. STM32 通用T2、T3、T4、T5定时器详解

    定时器初始化配置 void TIM3_Configuration(void)//1MS { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_DeI ...

  4. JDK1.9环境变量配置

    JAVA_HOME C:\Program Files\Java\jdk-9.0.1 JRE_HOME C:\Program Files\Java\jre-9.0.1 PATH .;%JAVA_HOME ...

  5. Mybatis(二):Mybatis的映射文件sqlmapper详解

    MyBatis 真正的力量是在映射语句中.这里是奇迹发生的地方.对于所有的力量,SQL 映射的 XML 文件是相当的简单.当然如果你将它们和对等功能的 JDBC 代码来比较,你会发现映射文件节省了大约 ...

  6. iOS-NSMutableParagraphStyle段落风格

    apple API: NS_CLASS_AVAILABLE(10_0, 6_0) @interface NSMutableParagraphStyle : NSParagraphStyle @prop ...

  7. Crypto++库安装、测试

    项目中需要使用到C++加密解密库,选择了Crypto++这个开源库,于是先安装并写一个小例子试试 一.下载 网址:http://www.cryptopp.com/#download 二.打开项目 下载 ...

  8. 密码学hash函数-SHA256-512

    [latexpage] Hash函数又称哈希函数.散列函数.杂凑函数.它是一种单向密码体制,即从一个从明文到密文的不可逆映射,只有加密过程,没有解密过程. Hash函数H将可变长度的数据块M作为输入, ...

  9. Spark Core源代码分析: RDD基础

    RDD RDD初始參数:上下文和一组依赖 abstract class RDD[T: ClassTag]( @transient private var sc: SparkContext, @tran ...

  10. Crontab使用方式

    Liunx系统的定时任务需要Crontab来完成 一.添加 添加定时脚本 crontab -e 或者直接编辑/etc/crontab文件进行任务添加 vim /etc/crontab 二.格式 三.举 ...