JVM总结(3)Class文件,类加载机制、编译过程

Java编译器先把Java代码编译为存储字节码的Class文件,再通过Class文件进行类加载。

Class类文件的结构

Java编译器可以把Java代码编译为存储字节码的Class文件

Class文件格式采用一种类似C语言结构体的伪结构来存储数据。这种伪结构中只有两种数据类型:无符号数和表。整个Class文件本质上就是一张表。

无符号数:属于基本数据类型,以u1、u2、u4分别代表1个字节、2个字节、4个字节。

表:由多个无符号数或其他表作为数据项构成的复合数据类型。

2、Class类文件结构详解:

  • 魔数:每个Class文件的头4个字节称为魔数,唯一的作用是确定这个文件是否能被虚拟机接受。如GIF\JPEG等在文件头都存有魔数。
  • 版本号:紧接着魔数的4个字节是Class文件的版本号。
  • 常量池:接着版本号的是常量池入口
  • 访问标志:接着常量池的是访问标志,标志着这个Class是类还是接口、是否为public等。
  • 类索引、父类索引与接口索引集合:之后接着这三个。
  • 字段表集合:接着是字段集合,用于描述接口或者类中声明的变量。
  • 方法表集合
  • 属性表集合:

一句话解释

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是JVM的类加载机制。

类加载时期

  • 在Java语言里,类的加载、连接和初始化过程都是在程序运行期间完成的。
  • Java语言运行期加载类的特性,为Java应用程序提供了高度的灵活性,比如一个本地程序可以在运行时从网络或其他地方加载一个二进制流作为程序代码的一部分。

类的生命周期

  • 类从被加载到虚拟机内存中开始,到卸载出内存为止,整个生命周期如上图。
  • 其中加载、验证、准备、初始化和卸载这5个阶段的顺序时确定的。
  • 解析阶段则不一定,可能在初始化之后才开始。

类与接口加载时的区别

只有一点,当一个类在初始化的时候,要求其父类全部都已经初始化过了,但一个接口在初始化的时候,并不要求其父接口全部都完成了初始化,只有在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。

3、类加载的详细过程

加载

  • 通过一个类的全限定名来获取定义此类的二进制字节流,JVM把这个阶段的动作放在了虚拟机外部的“类加载器”中实现。未指明从哪里获取,因此有各种花样,比如从JAR包、WAR包,或者网络,或者运行时计算生成等等。
  • 将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构。
  • 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。即对象类型数据(非对象实例数据)存在方法区。

验证

  • 验证的目的是确保Class文件的字节流中包含的信息不会危害虚拟机自身的安全,直接决定了Java虚拟机是否能承受恶意代码的攻击。
  • 验证阶段分为4个:文件格式验证,元数据验证,字节码验证,符合引用验证

准备

准备阶段为类变量在方法区中分配内存并设置类变量的零值

  • 这里只包含类变量(即被static修饰的变量),而不是实例变量
  • 实例变量会在对象实例化时随着对象一起分配在Java堆中
  • 比如 public static int value =123;在准备阶段过后value=0,只有在初始化阶段之后,value才等于123.

解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程

  • 符号引用也是描述所引用目标的,但引用的目标并不一定以及加载在内存中
  • 直接引用是指针、句柄这种,直接引用的目标必定以及在内存中存在。

初始化

初始化时类加载的最后一步,根据程序员的主观去初始化类变量和其他资源

4、类加载器ClassLoader

  • 虚拟机把类加载阶段中的通过一个类的全限定名来获取定义此类的二进制字节流这个动作放在了虚拟机外部的“类加载器”中实现。
  • 对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性
  • 比较两个类是否“相等”,只有在这个两个类是由同一个类加载器加载的前提下才有意义。

Java类的加载过程

Java类的加载过程应用了双亲委派模型

双亲委派模型

绝大部分Java程序都会用到以下3种系统提供的类加载器

  • 启动类加载器
  • 扩展类加载器
  • 应用程序类加载器

工作流程

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。

好处

Java类随着它的类加载器一起具备了一种带有优先级的层次关系。

为什么需要双亲委派模型:

  • 例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱。
  • 如果不采用双亲委派模型,那么由各个类加载器自己去加载的话,那么系统中会存在多种不同的Object类。

Java代码的编译过程

代码编译是由Javac编译器来完成,流程如上图所示。

Javac的任务就是将Java源代码编译成Java字节码,也就是JVM能够识别的二进制代码,从表面看是将.java文件转化为.class文件。而实际上是将Java源代码转化成一连串二进制数字,这些二进制数字是有格式的,只有JVM能够真确的识别他们到底代表什么意思。

具体流程:

  • 词法分析:读取源代码,一个字节一个字节的读进来,找出这些词法中我们定义的语言关键词如:if、else、while等,识别哪些if是合法的哪些是不合法的。这个步骤就是词法分析过程。
  • 语法分析:就是对词法分析中得到的token流进行语法分析,这一步就是检查这些关键词组合在一起是不是符合Java语言规范。如if的后面是不是紧跟着一个布尔型判断表达式。
  • 语义分析:语法分析完成之后也就不存在语法问题了,语义分析的主要工作就是把一些难懂的,复杂的语法转化成更简单的语法。比如将foreach转化为for循环。
  • 字节码生成:将会根据经过注释的抽象语法树生成字节码,也就是将一个数据结构转化为另外一个数据结构,结果就是生成符合java虚拟机规范的字节码。

JVM总结(三)的更多相关文章

  1. JVM总括三-字节码、字节码指令、JIT编译执行

    JVM总括三-字节码.字节码指令.JIT编译执行 目录:JVM总括:目录 java文件编译后的class文件,java跨平台的中间层,JVM通过对字节码的解释执行(执行模式,还有JIT编译执行,下面讲 ...

  2. JVM系列三:JVM参数设置

    JVM系列三:JVM参数设置.分析   不管是YGC还是Full GC,GC过程中都会对导致程序运行中中断,正确的选择不同的GC策略,调整JVM.GC的参数,可以极大的减少由于GC工作,而导致的程序运 ...

  3. jvm系列 (三) ---锁的优化

    锁的优化 目录 jvm系列(一):jvm内存区域与溢出 jvm系列(二):垃圾收集器与内存分配策略 jvm系列(三):锁的优化 我的博客目录 锁的四种状态 从低到高,只能升级不能降级 无锁状态 偏向锁 ...

  4. JVM(三)内存回收(一)

    最近花了相当长一段时间在看Hotspot JVM的GC和内存分配,本节先总结和回顾一下内存回收的相关知识点,内存的分配放到下节再讨论. 一.什么是JVM的GC GC即Garbage Collectio ...

  5. 深入理解JVM(三)——配置参数

    JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...

  6. JVM学习--(三)配置参数

    JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...

  7. JVM(三)调优工具

    前言 给一个系统定位问题的时候,知识.经验是关键基础,数据是依据,工具是运用知识处理数据的手段.这里说的数据包括:运行日志.异常堆栈.GC日志.线程快照(threaddump/javacore文件). ...

  8. JVM学习三:JVM之类加载器之连接分析

    学习完类加载之加载篇后,让我们继续来看加载之连接,连接分为三个步骤:验证.准备和解析三步,我们将一一分析之. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 类加载完毕之后进入 ...

  9. 基于JDK1.8的JVM 内存结构【JVM篇三】

    目录 1.内存结构还是运行时数据区? 2.运行时数据区 3.线程共享:Java堆.方法区 4.线程私有:程序计数器.Java 虚拟机栈.本地方法栈 5.JVM 内存结构总结 在我的上一篇文章别翻了,这 ...

  10. JVM系列三(垃圾收集器).

    一.概述 1. 哪些内存需要回收 上篇文章 我们介绍了 Java 内存运行时区域的各个部分,其中程序计数器.虚拟机栈.本地方法栈三个区域随线程而生,随线程而灭,在这几个区域内就不需要过多考虑回收的问题 ...

随机推荐

  1. Modbus RTU 介绍

    S7-1200 Modbus RTU 通信概述 Modbus具有两种串行传输模式:分别为ASCII和RTU.Modbus是一种单主站的主从通信模式,Modbus网络上只能有一个主站存在,主站在Modb ...

  2. MyBatis OGNL表达式用法

    From<MyBatis从入门到精通> <!-- 4.7 OGNL用法 MyBatis常用的OGNL表达式: e1 or e2: e1 and e2 e1 == e2; e1 != ...

  3. 【题解】长度为素数的路径个数-C++

    Description 对于正整数n (3≤n<20),可以画出n阶的回形矩阵.下面画出的分别是3阶的,4阶的和7阶的回形矩阵: 对于n阶回形矩阵,从左上角出发,每步可以向右或向下走一格,走2* ...

  4. 在eclipse中利用正则表达式查找替换

    众所周知,eclipse是可以用正则表达式来进行查找的,那么怎么利用正则表达式进行替换呢? 方法也很简单,就是在Replace with: 里面输入$来代表捕获型括号的匹配结果,$1为第一个匹配结果, ...

  5. Java异常与处理机制

    Java的异常层次体系 Java的所有异常对象都派生自Throwable类,下层有两个分支:error和exception. Error分支描述Java运行时系统内部错误或资源耗尽错误,遇到派生自Er ...

  6. 个人永久性免费-Excel催化剂功能第69波-打造最专业易用的商务图表库,即点即用的高级Excel图表

    Excel很大一块细分领域是图表,数据分析的末端,数据展示环节,精美恰当的图表,能够为数据分析数据结论带来画龙点睛的一笔.Excel催化剂简单内置了图表库,利用已经做好的模板式的图表示例,可快速复制使 ...

  7. Excel催化剂开源第6波-Clickonce部署之自动升级瘦身之术

    Clickonce无痛自动更新是我最喜欢使用VSTO开发并Clickonce部署的特性之一,但这个自动更新,通常会更新整个程序文件,包含所有的引用dll和一些资源文件等. 一般来说,我们更新的都是主程 ...

  8. MYSQL数据库约束类型

    07.14自我总结 MYSQL数据库约束类型 一.主键约束(primary key) 主键约束要求主键列的数据唯一,并且不能为空.主键分为两种类型:单字段主键和多字段联合主键. 1.单字段主键 写法 ...

  9. MyBatis一对多和多对多xml配置

    MyBatis一对多和多对多xml配置 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ma ...

  10. Spark学习之第一个程序 WordCount

    WordCount程序 求下列文件中使用空格分割之后,单词出现的个数 input.txt java scala python hello world java pyfysf upuptop wintp ...