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
}
#以上#
分享到:
相关推荐
详细介绍了JVM执行子系统的工作原理,包括类文件结构与字节码指令(Class类文件结构、JVM字节码指令简介)、JVM类加载机制(类加载器、类加载时机、类加载过程)、字节码执行引擎(运行时候的栈结构、方法调用、方法...
class的执行在Sun JDK中有解释执行和编译为机器码执行两种方式,其中编译为机器码又分为client和server两种模式。Sun JDK为了提升class的执行效率,对于解释执行和编译为机器码执行都设置了很多的优化策略。 Java...
JVM 是 Java 程序的运行环境,学习 JVM,方能了解 Java 程序是如何被执行的,为进一步深入底层原理乃至程序性能调优打好基础。通过学习这门课程,你将掌握:1. JVM 内存结构的组成、各部分功能作用,学会利用内存...
如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个 类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进JVM里面来。 ② 方法区 方法区 是用于存放类似于元数据信息方面的数据的,比如类...
Class 类文件结构、字节码指令、类加载机制以及基于栈的字节码解释执行引擎
包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码 第1讲 说在前面的话 免费 00:05:07 第2讲 整个部分要讲的内容说明 免费 00:06:58 第3讲...
1、jvm组成以工作流程 jvm组成 类装载器、运行时数据区(内存模型)、字节码执行引擎 工作大致流程 首先我们的java类编译成class类文件,当我们的class... 类加载器将class加载到运行时数据区,然后字节码执行引擎工作
文章目录Class 文件格式字节码Class类的本质Class文件格式类加载机制加载验证准备解析初始化类加载器双亲委派机制栈桢JVM方法调用详解方法解析静态分派动态分派参考 Class 文件格式 一般情况下Java代码执行流程如下...
类加载器从源文件(通常是.class 或 .jar文件)获得不依赖平台的字节码,然后将它们加载到JVM内存空间,所以它们能被解释和执行。默认状态下,应用程序的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以...
全面理解JVM虚拟机 内容简介: 1、JVM主要学些什么 2、CLASS文件规范 3、类加载 4、执行引擎 5、GC垃圾回收 6、GC情况分析实例
Mini-JVM首先会从classpath中加载主类的class文件,然后找到main方法的字节码解释执行;执行过程中如果遇到新的类符号引用,则会通过全限定性名再从classpath中加载新的类文件,以此类推; 控制台输出、多线程功能...
JVM=类加载器classloader+执行引擎executionengine+运行时数据区域runtimedataarea首先Java源代码文件被Java编译器编译为字节码文件,然后JVM中的类加载器加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中
类加载 执行方法 创建对象 堆空间分代划分 outOfMemory异常 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html 可以看jvm参数查看网址 Direct buffer memory : 直接内存太大(-XX:...
/ 112 5.2.5 服务器JVM进程崩溃 / 113 5.3 实战:Eclipse运行速度调优 / 114 5.3.1 调优前的程序运行状态 / 114 5.3.2 升级JDK 1.6的性能变化及兼容问题 / 117 5.3.3 编译时间和类加载时间的优化 / 122 5.3.4 ...
在永久域中jvm则存储class和method对象。就配置而言,永久域是一个独立域并且不认为是堆的一部分。 下面介绍如何控制这些域的大小。可使用-Xms和-Xmx 控制整个堆的原始大小或最大值。 下面的命令是把初始大小设置...
第65节Class文件简介和发展历史 [免费观看] 00:11:26分钟 | 第66节Class文件结构概述 [免费观看] 00:16:50分钟 | 第67节Class文件设计理念以及意义 [免费观看] 00:13:41分钟 | 第68节文件结构-魔数 [免费观看] 00...
java ClassLoader的学习 java是一门解释执行的语言,由开发人员编写好的java源文件先编译成字节码文件.class... 一个类如果要被JVM所调度执行,必须先把这个类加载到JVM内存里,java.lang下有个很重要的类ClassL
Class.forName(xxx.xx.xx) 返回的是一个类 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段
初始化:在准备阶段已经赋过一个系统要求的初始值,而在初始化阶段则通过程序制定的主管计划去初始化变量和其他资源,从另一个角度理解就是 执行类构造器的()方法 .()方法是由编译器自动收集类中的所有变量的复制动作和...