`
daibalusu
  • 浏览: 344527 次
文章分类
社区版块
存档分类
最新评论

JVM class加载和执行

 
阅读更多

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执行子系统原理

    详细介绍了JVM执行子系统的工作原理,包括类文件结构与字节码指令(Class类文件结构、JVM字节码指令简介)、JVM类加载机制(类加载器、类加载时机、类加载过程)、字节码执行引擎(运行时候的栈结构、方法调用、方法...

    JVM中编译Class、内存回收、多线程原理和使用

    class的执行在Sun JDK中有解释执行和编译为机器码执行两种方式,其中编译为机器码又分为client和server两种模式。Sun JDK为了提升class的执行效率,对于解释执行和编译为机器码执行都设置了很多的优化策略。 Java...

    Java进阶教程解密JVM视频教程

    JVM 是 Java 程序的运行环境,学习 JVM,方能了解 Java 程序是如何被执行的,为进一步深入底层原理乃至程序性能调优打好基础。通过学习这门课程,你将掌握:1. JVM 内存结构的组成、各部分功能作用,学会利用内存...

    大白话带你认识JVM.pdf

    如果 JVM 想要执行这个 .class 文件,我们需要将其装进一个 类加载器 中,它就像一个搬运工一样,会把所有的 .class 文件全部搬进JVM里面来。 ② 方法区 方法区 是用于存放类似于元数据信息方面的数据的,比如类...

    JVM执行子系统.pdf

    Class 类文件结构、字节码指令、类加载机制以及基于栈的字节码解释执行引擎

    深入理解JVM内存结构及运行原理全套视频加资料.txt

    包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码  第1讲 说在前面的话 免费 00:05:07  第2讲 整个部分要讲的内容说明 免费 00:06:58  第3讲...

    JVM调优基本概念以及调优的工作流程

    1、jvm组成以工作流程 jvm组成 类装载器、运行时数据区(内存模型)、字节码执行引擎 工作大致流程 首先我们的java类编译成class类文件,当我们的class... 类加载器将class加载到运行时数据区,然后字节码执行引擎工作

    【JVM和性能优化】3.JVM的执行子系统

    文章目录Class 文件格式字节码Class类的本质Class文件格式类加载机制加载验证准备解析初始化类加载器双亲委派机制栈桢JVM方法调用详解方法解析静态分派动态分派参考 Class 文件格式 一般情况下Java代码执行流程如下...

    掌握Java类加载器

    类加载器从源文件(通常是.class 或 .jar文件)获得不依赖平台的字节码,然后将它们加载到JVM内存空间,所以它们能被解释和执行。默认状态下,应用程序的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以...

    全面理解JVM虚拟机.rar

    全面理解JVM虚拟机 内容简介: 1、JVM主要学些什么 2、CLASS文件规范 3、类加载 4、执行引擎 5、GC垃圾回收 6、GC情况分析实例

    java8rt.jar源码-mini-jvm:Go语言实现的JVM,实现了部分字节码的解释执行,学习JVM使用

    Mini-JVM首先会从classpath中加载主类的class文件,然后找到main方法的字节码解释执行;执行过程中如果遇到新的类符号引用,则会通过全限定性名再从classpath中加载新的类文件,以此类推; 控制台输出、多线程功能...

    JVM——Java虚拟机架构

    JVM=类加载器classloader+执行引擎executionengine+运行时数据区域runtimedataarea首先Java源代码文件被Java编译器编译为字节码文件,然后JVM中的类加载器加载完毕之后,交由JVM执行引擎执行。在整个程序执行过程中

    java8源码-jvm-study:jvm-study

    类加载 执行方法 创建对象 堆空间分代划分 outOfMemory异常 https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html 可以看jvm参数查看网址 Direct buffer memory : 直接内存太大(-XX:...

    深入理解_Java_虚拟机 JVM_高级特性与最佳实践

    / 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 ...

    resin-jvm 调优

    在永久域中jvm则存储class和method对象。就配置而言,永久域是一个独立域并且不认为是堆的一部分。 下面介绍如何控制这些域的大小。可使用-Xms和-Xmx 控制整个堆的原始大小或最大值。 下面的命令是把初始大小设置...

    深入理解Java虚拟机视频教程(jvm性能调优+内存模型+虚拟机原理)视频教程

    第65节Class文件简介和发展历史 [免费观看] 00:11:26分钟 | 第66节Class文件结构概述 [免费观看] 00:16:50分钟 | 第67节Class文件设计理念以及意义 [免费观看] 00:13:41分钟 | 第68节文件结构-魔数 [免费观看] 00...

    Java类加载器加载类顺序

    java ClassLoader的学习  java是一门解释执行的语言,由开发人员编写好的java源文件先编译成字节码文件.class...  一个类如果要被JVM所调度执行,必须先把这个类加载到JVM内存里,java.lang下有个很重要的类ClassL

    Class.forName

    Class.forName(xxx.xx.xx) 返回的是一个类 Class.forName(xxx.xx.xx);的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段

    关于JVM的总结

    初始化:在准备阶段已经赋过一个系统要求的初始值,而在初始化阶段则通过程序制定的主管计划去初始化变量和其他资源,从另一个角度理解就是 执行类构造器的()方法 .()方法是由编译器自动收集类中的所有变量的复制动作和...

Global site tag (gtag.js) - Google Analytics