JVM之java源码编译机制
2017-10-22 10:06
344 查看
前言:
java程序运行在JVM之上,JVM的运行状况对于java程序会产生很大的影响,所以掌握JVM中关键的机制对与编写稳定的,高性能的java程序至关重要!JVM标准结构图
JVM负责装载class文件并执行,首先要掌握以下三个问题
1.JDK是如何将java代码编译为class文件的?
2.如何装载class文件?
3.如何执行class?
将源码编译class文件的实现取决于各个JVM实现或 各种源码编译器
class文件通常由类加载器classLoader来完成加载
class的执行在SUN JDK中有解释执行和编译为机器码执行两种方式。
本文主要详细介绍java源码编译机制
java源码编译机制
JVM规范中定义了class文件的格式,但没有规定java源码如何编译为class文件,各厂商都会实现将符合java语言规范的源码编译为class文件的编译器,如Sun JdK中就是javac,javac将源码编译为class文件的步骤如图所示
下面简单介绍三个步骤
1.分析和输入到符号表(Parse and Enter)
Parse所做的为词法和语法分析词法分析:
将代码字符串转变为token序列
token就是把程序的语句进行类似分词得到的单词
语法分析:
根据语法由tiken序列生成抽象语法树
Enter
做的是将符号输入到符号表
通常包括确定类的超类型和接口,根据需要添加默认构造器,将类中出现的符号输入类自身的符号表中去
2.注解处理(Annotation Processing)
该步骤主要用于处理用户自定义的注解 ,如以下代码import lombok.Getter; public class User{ private @Getter String name; public static void main(String args[]){ String mango="mango"; String s="abc"+mango+"def"; System.out.println(s); } }编译时引入Lombok对User.java进行编译后,可以通过javap查看class文件自动生成了public String getUsername()方法
javac -cp lombok-1.16.16.jar User.java
javap User
关于Lombok 看考http://blog.csdn.net/ghsau/article/details/52334762
在Annotation Processing进行后,再次进入了Pare and Enter步骤
3.语义分析和生成class文件(Analyse and Generate)
Analyse语义分析:基于抽象语法树进行一系列的语义分析1.包括将树中的名字,表达式等变量,方法,类型联系到一起
2.检查变量使用前是否已声明
3.检查checked exception都被捕获或抛出
4.将泛型java转为普通java
5.将含有语法糖的语法树改为含有简单语法的语言结构的的语法树,如for exch,自动装箱拆箱等
.......
完成了语义分析后,就开始生成class文件。
生成的步骤为
1.将实例成员初始化器收集到构造器中
2.将静态成员初始化器收集为《clinit》
3.将抽象语法树生成字节码,采用的方法为后续遍历 语法树
4.进行最后的少量代码转换(例如string相加转变为stringBuilder相加)
5.从符号表生成class文件
除了javac外,还可以通过Eclipse Complier for java 或jikes等编译器来讲java文件编译为class文件
class文件结构
class文件结构不仅仅存放了字节码,还包含了很多辅助jvm来执行的clasas附加信息,一个class文件包含了以下信息结构信息
包含class文件格式版本后及各部分的数量与大小信息元数据
java源码中声明与常量的信息,如类、超类,实现的接口声明的信息,域field与方法声明信息和常量池方法信息
java源码语句与表达式对应的信息以一段简单的代码来说明class文件结构
public class Foo { private static final int MAX_COUNT = 1000; private static int count = 0; public int bar() throws Exception{ if(++count<MAX_COUNT){ count = 0; throw new Exception("count overflow"); } return count; } }javac -g Foo.java
编译后,使用
javap -c -s -l -verbose Foo 查看编译后的class文件
E:\test>javap -c -s -l -verbose Foo Classfile /E:/test/Foo.class Last modified 2017-10-22; size 607 bytes MD5 checksum f7e8e8b3a4f1f3a7acefb5253d8f43df Compiled from "Foo.java"
//元数据:类/继承的超类/实现的接口的声明信息 public class Foo minor version: 0
//50表示jdk 6 ,51表示jdk 7, 52表示jdl 8 major version: 52 flags: ACC_PUBLIC, ACC_SUPER
//元数据:常量池 Constant pool: #1 = Methodref #7.#27 // java/lang/Object."<init>":()V #2 = Fieldref #3.#28 // Foo.count:I #3 = Class #29 // Foo #4 = Class #30 // java/lang/Exception #5 = String #31 // count overflow #6 = Methodref #4.#32 // java/lang/Exception."<init>":(Ljava/lang/String;)V #7 = Class #33 // java/lang/Object #8 = Utf8 MAX_COUNT #9 = Utf8 I #10 = Utf8 ConstantValue #11 = Integer 1000 #12 = Utf8 count #13 = Utf8 <init> #14 = Utf8 ()V #15 = Utf8 Code #16 = Utf8 LineNumberTable #17 = Utf8 LocalVariableTable #18 = Utf8 this #19 = Utf8 LFoo; #20 = Utf8 bar #21 = Utf8 ()I #22 = Utf8 StackMapTable #23 = Utf8 Exceptions #24 = Utf8 <clinit> #25 = Utf8 SourceFile #26 = Utf8 Foo.java #27 = NameAndType #13:#14 // "<init>":()V #28 = NameAndType #12:#9 // count:I #29 = Utf8 Foo #30 = Utf8 java/lang/Exception #31 = Utf8 count overflow #32 = NameAndType #13:#34 // "<init>":(Ljava/lang/String;)V #33 = Utf8 java/lang/Object #34 = Utf8 (Ljava/lang/String;)V {
//Enter:将符号输入到符号表是生成的默认构造器方法 public Foo(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LFoo; //bar方法的元数据信息 public int bar() throws java.lang.Exception; descriptor: ()I flags: ACC_PUBLIC Code: stack=3, locals=1, args_size=1
//方法对应的字节码信息 0: getstatic #2 // Field count:I 3: iconst_1 4: iadd 5: dup 6: putstatic #2 // Field count:I 9: sipush 1000 12: if_icmpge 29 15: iconst_0 16: putstatic #2 // Field count:I 19: new #4 // class java/lang/Exception 22: dup 23: ldc #5 // String count overflow 25: invokespecial #6 // Method java/lang/Exception."<init>":(Ljava/lang/String;)V 28: athrow 29: getstatic #2 // Field count:I 32: ireturn
//行号信息 LineNumberTable: line 5: 0 line 6: 15 line 7: 19 line 9: 29
//局部变量信息 LocalVariableTable: Start Length Slot Name Signature 0 33 0 this LFoo; StackMapTable: number_of_entries = 1 frame_type = 29 /* same */
//异常处理器表 Exceptions: throws java.lang.Exception static {}; descriptor: ()V flags: ACC_STATIC Code: stack=1, locals=0, args_size=0 0: iconst_0 1: putstatic #2 // Field count:I 4: return LineNumberTable: line 3: 0 } SourceFile: "Foo.java"
从上可见,class文件是个完整的自描述文件,字节码在其中只占了很小的一部分。
参考:分布式java应用 基础与实践
相关文章推荐
- jvm 之 java源码编译机制-感想
- JVM之---Java源码编译机制
- 深入JVM【1】java源码编译机制
- Java JVM:编译加载机制与自定义类加载器
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
- 【总结】深入JVM之源码编译机制
- jvm详解-java源码编译
- JAVA源码编译机制
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
- Java源码编译机制、类加载机制、类执行机制
- 初探Java中JVM的类加载机制之原理简析
- 【Java面试题】46 描述一下JVM加载class文件的原理机制?
- jvm系列(一):java类的加载机制
- 哈希(Hash)相关---Java中的Hash机制(HashMap、HashSet及对其源码解析
- JVM核心机制_深入类加载器JAVA220-223
- JVM系列:四、Java类加载机制总结
- Java源码,编译后会生成一种.class文
- Java提高篇——JVM加载class文件的原理机制
- Java技术专题之JVM逻辑内存回收机制研究图解版
- ubuntu 12.04 amd64 编译android源码的JAVA环境配置