Written by 蒋彪 20120427
1. Class load的流程
加载à验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载
其中初始化由new 命令完成
验证主要是验证字节码的正确性
这边的细节理论性太强,不多说
整个流程由class loader完成,class loader是双亲委托,父类上溯load。不多废话。
但是据说OSGI不是这样,OSGI的类加载是网状的,每个bulder一个加载器(怎么做到的?有时间研究研究)
一个小例子,两个线程在同时初始化一个class的时候,陷入死锁
public class Test2 {
static class Aim {
static{
if(true) {
System.out.println(Thread.currentThread() + " initing");
while(true){}
}
}
}
public static void main(String atgs[]) {
Runnable test = new Runnable(){
@Override
public void run() {
System.out.println(Thread.currentThread() + " start");
Aim aim = new Aim();
System.out.println(Thread.currentThread() + " over");
}
};
Thread thread1 = new Thread(test);
Thread thread2 = new Thread(test);
thread1.start();
thread2.start();
}
}
2. 字节码的执行
字节码加载到JVM里面以后,静态方法签名都被固化了。
但是实际运行的对象引用是运行时链接。
2.1 比如重写
public class ReWriteSample {
static class Human{
}
static class Boy extends Human {
}
public static void test(Human human) {
System.out.println("human");
}
public static void test(Boy boy) {
System.out.println("boy");
}
/**
* @param args
*/
public static void main(String[] args) {
Human human = new Human();
Human boy = new Boy();
test(human);
test(boy);
}
}
运行结果是两个human
查看代码编译之后的字节码
public class ReWriteSample extends java.lang.Object
SourceFile: "ReWriteSample.java"
InnerClass:
#50= #40 of #1; //Boy=class ReWriteSample$Boy of class ReWriteSample
#51= #37 of #1; //Human=class ReWriteSample$Human of class ReWriteSample
minor version: 0
major version: 50
Constant pool:
const #1 = class #2; // ReWriteSample
const #2 = Asciz ReWriteSample;
const #3 = class #4; // java/lang/Object
const #4 = Asciz java/lang/Object;
const #5 = Asciz <init>;
const #6 = Asciz ()V;
const #7 = Asciz Code;
const #8 = Method #3.#9; // java/lang/Object."<init>":()V
const #9 = NameAndType #5:#6;// "<init>":()V
const #10 = Asciz LineNumberTable;
const #11 = Asciz LocalVariableTable;
const #12 = Asciz this;
const #13 = Asciz LReWriteSample;;
const #14 = Asciz test;
const #15 = Asciz (LReWriteSample$Human;)V;
const #16 = Field #17.#19; // java/lang/System.out:Ljava/io/PrintS
tream;
const #17 = class #18; // java/lang/System
const #18 = Asciz java/lang/System;
const #19 = NameAndType #20:#21;// out:Ljava/io/PrintStream;
const #20 = Asciz out;
const #21 = Asciz Ljava/io/PrintStream;;
const #22 = String #23; // human
const #23 = Asciz human;
const #24 = Method #25.#27; // java/io/PrintStream.println:(Ljava/l
ang/String;)V
const #25 = class #26; // java/io/PrintStream
const #26 = Asciz java/io/PrintStream;
const #27 = NameAndType #28:#29;// println:(Ljava/lang/String;)V
const #28 = Asciz println;
const #29 = Asciz (Ljava/lang/String;)V;
const #30 = Asciz LReWriteSample$Human;;
const #31 = Asciz (LReWriteSample$Boy;)V;
const #32 = String #33; // boy
const #33 = Asciz boy;
const #34 = Asciz LReWriteSample$Boy;;
const #35 = Asciz main;
const #36 = Asciz ([Ljava/lang/String;)V;
const #37 = class #38; // ReWriteSample$Human
const #38 = Asciz ReWriteSample$Human;
const #39 = Method #37.#9; // ReWriteSample$Human."<init>":()V
const #40 = class #41; // ReWriteSample$Boy
const #41 = Asciz ReWriteSample$Boy;
const #42 = Method #40.#9; // ReWriteSample$Boy."<init>":()V
const #43 = Method #1.#44; // ReWriteSample.test:(LReWriteSample$Human;)V
const #44 = NameAndType #14:#15;// test:(LReWriteSample$Human;)V
const #45 = Asciz args;
const #46 = Asciz [Ljava/lang/String;;
const #47 = Asciz SourceFile;
const #48 = Asciz ReWriteSample.java;
const #49 = Asciz InnerClasses;
const #50 = Asciz Boy;
const #51 = Asciz Human;
{
public ReWriteSample();
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 2: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LReWriteSample;
public static void test(ReWriteSample$Human);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #22; //String human
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
8: return
LineNumberTable:
line 13: 0
line 14: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 human LReWriteSample$Human;
public static void test(ReWriteSample$Boy);
Code:
Stack=2, Locals=1, Args_size=1
0: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #32; //String boy
5: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
8: return
LineNumberTable:
line 17: 0
line 18: 8
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 boy LReWriteSample$Boy;
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=3, Args_size=1
0: new #37; //class ReWriteSample$Human
3: dup
4: invokespecial #39; //Method ReWriteSample$Human."<init>":()V
7: astore_1
8: new #40; //class ReWriteSample$Boy
11: dup
12: invokespecial #42; //Method ReWriteSample$Boy."<init>":()V
15: astore_2
16: aload_1
//静态调用
17: invokestatic #43; //Method test:(LReWriteSample$Human;)V
20: aload_2
21: invokestatic #43; //Method test:(LReWriteSample$Human;)V
24: return
LineNumberTable:
line 24: 0
line 25: 8
line 26: 16
line 27: 20
line 28: 24
LocalVariableTable:
Start Length Slot Name Signature
0 25 0 args [Ljava/lang/String;
8 17 1 human LReWriteSample$Human;
16 9 2 boy LReWriteSample$Human;
}
2.2 再比如重载
代码稍微改一下
public class ReWriteSample {
static class Human{
public void SayHello() {
System.out.println("human");
}
}
static class Boy extends Human {
public void SayHello() {
System.out.println("boy");
}
}
public static void test(Human human) {
human.SayHello();
}
public static void test(Boy boy) {
boy.SayHello();
}
/**
* @param args
*/
public static void main(String[] args) {
Human human = new Human();
Human boy = new Boy();
test(human);
test(boy);
}
}
我们查看字节码
public static void test(ReWriteSample$Human);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
//虚拟调用,会在运行态沿着继承树查找对象
1: invokevirtual #16; //Method ReWriteSample$Human.SayHello:()V
4: return
LineNumberTable:
line 17: 0
line 18: 4
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 human LReWriteSample$Human;
public static void test(ReWriteSample$Boy);
Code:
Stack=1, Locals=1, Args_size=1
0: aload_0
1: invokevirtual #24; //Method ReWriteSample$Boy.SayHello:()V
4: return
LineNumberTable:
line 21: 0
line 22: 4
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 boy LReWriteSample$Boy;
3. 基于stack的字节码执行引擎
一般来说指令集有基于寄存器和基于栈的。
JVM为了和平台无关性,选用了基于栈的指令集。
比如
/**
* @param args
*/
public static void main(String[] args) {
int i =1;
int j=0;
int k = (i + j)*j;
}
字节码如下:
public static void main(java.lang.String[]);
Code:
Stack=2, Locals=4, Args_size=1
//第一个参数压栈
0: iconst_1
1: istore_1
//第二个参数压栈
2: iconst_0
3: istore_2
//两个参数出栈
4: iload_1
5: iload_2
//两个参数相加以后保留在变量池中
6: iadd
//第三个参数出栈
7: iload_2
//相乘
8: imul
//压栈,返回
9: istore_3
10: return
LineNumberTable:
line 28: 0
line 29: 2
line 30: 4
line 32: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 args [Ljava/lang/String;
2 9 1 i I
4 7 2 j I
10 1 3 k I
}
#以上#