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 }
#以上#