JVM学习系列(1)——Java代码是如何执行的

Java程序的通用执行过程

学习Java编程语言学习时的最初的示例程序一般都是HelloWorld。我们来看一个HelloWorld.java的示例:

public class HelloWorld{ 
    
   public static void main(String args[])
   { 
      System.out.println("Hello World!"); 
   }

} 

在执行代码前,我们需要对其进行编译,执行命令为:

javac HelloWorld.java

就能得到一个名为HelloWorld.class的文件。
接下来,我们运行java命令就可以了执行它。

java HelloWorld

就可以了看到执行结果了:

Hello World!

以上,就是一个通用的Java程序执行过程。想要了解更多细节,就需要学习下JVM的一些知识。下面,我们来看下一个标准的JVM,应该是什么样子的。

JVM标准结构

首先我们来看一个JVM的标准结构。


JVM标准结构.jpg

学习JVM需要了解

  1. 如何将Java代码编译、装载、执行class文件;
  2. 如何分配和回收内存;
  3. 线程间资源同步和线程间交互的机制。
    本文主要介绍第1点,Java代码编译、装载、执行。这个过程,简单来讲,就是Class文件通过类加载器装入运行时数据区,然后通过执行引擎进行执行。下面我们从Java源码的编译入手,来看Class文件是怎么得到的。

JAVA源码的编译

我们编写的Java代码,都是.java的文件。在执行前,需要执行javac命令对其进行编译。编译主要有三个步骤:

  1. 分析和输入到符号表
  • 分析包括词法分析和语法分析。词法分析是把代码字符串转为token序列;语法分析是根据语法由token序列生成抽象语法树。
  • 输入过程为将符号输入到符号表,通常包括确定类的超类型和接口。根据需要添加默认构造器、将类中出现的符号输入类自身的符号表中。
  1. 注解处理
  • 注解处理主要是处理用户自定义的注解。一个注解处理器(javac工具中包含),以Java代码(或者编译过的字节码)作为输入,生成文件(通常是.java文件)作为输出。关于注解,我们需要一个单独的章节来学习,这里不再赘述。
  1. 语义分析和生成class文件
  • 语义分析主要是基于抽象语法树进行一系列语义分析,包括将语法树中的名字、表达式等元素与变量、方法、类型等联系到一起;检查变量使用前是否已经声明;推导泛型方法的类型参数;检查类型匹配性;消除无用代码。
  • 生成class的步骤:初始化;将抽象语法树生成字节码,进行少量的代码替换(如String相加转变为StringBuilder操作);最后从符号表生成class文件。
  1. Class文件的构成
  • 结构信息
    结构信息包括class文件格式版本号及各部分数量与大小的信息
  • 元数据
    可以认为元数据对应的是Java源码中“声明”与“常量”信息,主要有:类继承的超类,实现的接口的声明信息,域(Field)与方法声明信息和常量池。
  • 方法信息
    可以认为方法信息对应的就是Java源码中“语句”与“表达式”对应的信息,主要有:字节码、异常处理表、求值栈与局部变量区大小、求值栈的类型记录、调试用符号信息。

类文件的加载

类文件的加载有三个步骤:装载、连接、初始化。其中,连接的步骤有验证、准备和解析三个动作。


类文件加载.jpg
  • 类加载指的是class文件加载到jvm,并形成Class对象的机制,之后应用就可以对Class对象进行实例化并调用;
  • 装载和链接完成后,即将二进制的字节码转换为Class对象,初始化过程不是加载类时必须触发的,但最迟必须在初次主动使用对象前执行,其所做动作为给静态变量赋值,执行<clinit>()等。

类装载

  • Jvm通过类的全限定名(com.jd.ofc.coi.bean.OwOrder)及类加载器(ClassLoaderA实例)完成类的加载。同样也用这两个元素来标识一个被加载了的类。
  • 类名命名方式:
    –对于接口和非数组类,名称即为类名,此类型的类由所在的ClassLoader负责加载。
    –数组型的类,名称为”[”+(基本类型或L+引用类型名;),数组类型中的元素类型由所在的ClassLoader负责加载,但数组类则由jvm直接创造

链接(Link)

  • 链接过程负责对二进制字节码格式进行校验、初始化装载类中的静态变量及解析类中调用的接口、类。
    – 二进制字节码校验遵循Java Class File Format规范,格式不符抛出VerifyError;校验过程中如果要引用到其他类或接口也会加载;加载失败会抛出NoClassDefFoundError。
    – 完成校验后,JVM初始化类的静态变量,赋值。
    – 最后对类中的所有属性、方法验证,以确保要调用的属性、方法存在,并具备相应的权限。这个阶段失败会造成NoSuchMethodError、NoSuchFieldError等错误信息。

初始化(Initialize)

  • 初始化过程即执行类中的静态初始化代码、构造器代码即静态属性的初始化,以下四种情况的初始化过程会被触发执行:
    – 调用了new
    – 反射调用了类中的方法
    – 子类调用了初始化
    – JVM启动过程中指定的初始化类

类加载器

类加载器.jpg

Sun的jdk采用C++实现BootstrapClassloader,此类非ClassLoader的子类,代码中无法拿到该对象,其parent为null。
User-Defined ClassLoader是Java开发人员继承ClassLoader抽象类自行实现的ClassLoader,基于自定义的ClassLoader可加载非Classpath的jar及目录、还可以加载前对class文件做一些操作,如解密。

类加载的异常

  • CLassNotFoundException
    当前ClassLoader中加载类时未找到类文件。对位于System ClassLoader中的类,如果不在Classpath中,就会报这个异常。
  • NoClassDefFoundError
    原因是加载的类中引用到的另外的类不存在。
  • ClassCastException
    类型转换错误,产生原因众多。

类执行

类执行方式主要有三种,字节码解释执行,编译执行,反射执行。
在开始介绍之前,我们先了解下编译执行和解释执行分别是什么。

编译型语言

是一次性编译成机器码,脱离开发环境独立运行,所以运行效率较高,但是由于编译成的是特定平台上机器码,所以可移植性差。编译型语言的典型代表有C、C++、FORTRAN、Pascal等。

解释型语言

是专门的解释器对源程序逐行解释成特定平台的机器码并执行的语言。解释型语言通常不会进行整体性的编译和链接处理,解释语言相当于把编译型语言的编译和解释过程混合到了一起同时完成。于是,每次执行解释型语言的程序都要进行一次编译,因此解释型语言的程序运行效率通畅较低,而且不能脱离解释器独立运行。但解释型语言跨平台容易,只需要提供特定的平台解释器即可。解释型语言可以方便的进行程序的移植,但是以牺牲程序的执行效率为代价的。解释型语言的典型代表有Ruby、Python等。

Java语言

Java语言的特殊性在于用Java编写的程序先要经过编译,但不会生成特定平台的机器码,而是生成一种平台无关的字节码,即.class文件。这种字节码并不是可执行的,必须通过Java编译器来编译执行。因此可以认为Java即是编译型语言也是解释型语言。
Java语言里解释执行字节码文件的是Java虚拟机JVM。JVM是可执行Java字节码文件的虚拟计算机。所有平台上的JVM想编译器提供相同相同的编程接口,而编译器只需要面向虚拟机,生成虚拟机能理解的代码,由虚拟机来解释执行。在一些虚拟机的实现中,还会将虚拟机代码转换成特定系统的机器码执行,从而提高执行效率。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容