一:JVM的概述
1.为什么要学习JVM2.虚拟机3.JVM的作用
作用特点 4.JVM的位置5.JVM的分类6.各个组成部分的用途7.Java 代码的执行流程8.JVM 架构模型 二:JVM 结构-类加载
1. 类加载子系统2.类加载的角色3.类加载过程
加载连接初始化 4.类加载器5.双亲委派机制6.类的主动使用/被动使用 三、JVM 运行时数据区
运行时数据区的概念和组成程序计数器java虚拟机栈本地方法栈java堆内存方法区
一:JVM的概述 1.为什么要学习JVMJVM是java底层代码的运行机制,虽然我们不学习jvm,也可以写出漂亮的代码,但是在一些面试过程中,不懂JVM会被面试官虐的体无完肤。一切知识点都是为了面试而准备,当然,这也是作为一个中高级程序员的必修之课。学会了JVM,才能清楚项目管理和性能调优的基本原理。
2.虚拟机 1.所谓虚拟机(Virtual Machine),就是一台虚拟的计算机。它是一款软件,用来执 行一系列虚拟计算机指令。大体上,虚拟机可以分为系统虚拟机和程序虚拟机。
2.大名鼎鼎的 VMware 就属于系统虚拟机,它是完全对物理计算机的仿真,提供了一 个可运行完整操作系统的软件平台。程序虚拟机典型的代表就是 java 虚拟机了,它专门为 执行某个单个计算机程序而设计。在 java 虚拟机中执行的指令我们称为 java 字节码指令。
3.Java 虚拟机是一种执行 java 字节码文件的虚拟计算机,它拥有独立的运行机制。
4.Java 技术的核心就是 java 虚拟机,因为所有的 java 程序都运行在 java 虚拟机内部。
我们都知道JVM是java代码的运行环境,他是JDK不可或缺的一部分,而java虚拟机就是二进制字节码的运行环境,负责装在字节码到内部。,解释/编译为对应平台上的机器码指令执行。对每一条 java 指令,java 虚拟机中都有详细定义。如怎么取操作数,怎么处理操作数,处理结果放在哪儿
- 一次编译,到处运行自动内存管理自动垃圾回收功能
现在的 JVM 不仅可以执行 java 字节码文件,还可以执行其他语言编译后的字节码文件,是一 个跨语言平台。
JVM 是运行在操作系统之上的,它与硬件没有直接的交互。
- 类加载器(ClassLoader)运行时数据区(Runtime Data Area)执行引擎(Execution Engine)本地库接口(Native Interface)
简图:
详细图:
程序在执行之前先要把 java 代码转换成字节码(class 文件),jvm 首先需要把字节码通过一定的方式 类加载器(ClassLoader) 把文件加载到内存中 的运行时数据区(Runtime Data Area),而字节码文件是 jvm 的一套指 令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器将字节码翻译成底层系统指令再交由 CPU 去执行,而这个过程中需要调用其他语言的接口来实现整个程序的功能,这就是这 4 个主要组成部分的职责与功能
而我们通常所说的 JVM 组成指的是运行时数据区(Runtime Data Area),因为通常需要程序员调试分析的区域就是“运行时数据区”,或者 更具体的来说就是“运行时数据区”里面的 Heap(堆)模块。
JVM 主要任务就是负责将字节码装载到其内部,解释/编译为对应平台上的机器指令执行。JVM 使用类加载器(Class Loader)装载 class 文件。 类加载完成后,会进行字节码校验,字节码校验通过之后 JVM 解释器会把字节 码翻译成机器码交由操作系统执行。
Java 编译器输入的指令流基本上是一种基于栈的指令集架构,另一种指令集架构 是基于寄存器的指令集架构.
这两种架构之间的区别:
基于栈式架构的特点
- 设计和实现更简单,适用于资源受限的系统.使用零地址指令方式分配,其执行过程依赖于操作栈,指令集更小,编译器容易实现不需要硬件支持,可移植性好,更好实现跨平台.
基于寄存器式架构特点:
- 指令完全依赖于硬件,可移植性差.性能优秀,执行更高效.完成一项操作使用的指令更少.
使用 javap -v class 文件可以将 class 文件反编译为指令集. 所以由于跨平台的设计,Java 指令集都是根据栈来设计的,不同 CPU 架构不同, 所以不能设计为基于寄存器的. 优点是跨平台,指令集小,编译器容易实现. 缺点是性能下降,实现同样功能需要更多的指令.
类加载器子系统负责从文件系统或者网络中加载 class 文件。
- class file 存在于硬盘上,可以理解为设计师画在纸上的模板,而最终这个模板在执行的时候是要加载 JVM 当中来,根据这个模板实例化出 n 个一模一样的实例.class file 加载到 JVM 中,被称为 DNA 元数据模板,放在方法区中.在.class–>JVM–>最终称为元数据模板,此过程就要有一个运输工具(类加 载器 Class Loader),扮演一个快递员的角色.
- 根据类的地址,从硬盘上读取类的信息,将信息读入到方法区,生成Class类的对象
验证: 验证字节码文件格式是否是当前虚拟机所支持的文件格式,语法格式
准备: 为静态成员分配默认值(int 默认值0) 注意static final在编译期间赋值
解析: 将字节码中符号引用 替换成 直接引用
类在什么时候开始初始化?
- )创建类的实例,也就是 new 一个对象访问某个类或接口的静态变量,或者对该静态变量赋值调用类的静态方法反射(Class.forName(“”))初始化一个类的子类(会首先初始化子类的父类)
类初始化的数据
- 先初始化静态的,多个静态的按照从上向下的顺序执行,如果类有父类,则先初始化父类的静态,然后是子类.如果是创建对象,先调用父类的构造方法,然后是子类自己的构造方法
从JVM来说,类加载器可以分为两种
- 启动类加载器(不是java语言写的)其他所有类加载器(都是java语言写的,且全部继承自抽象类java.lang.ClassLoader.)
站在开发者的角度:
启动类加载器(引导类加加载器)
这个类加载器使用 C/C++语言实现,嵌套在 JVM 内部.它用来加载 java 核心类库。负责加载扩展类加载器和应用类加载器。加载
扩展类加载类器
是由java语言实现的 继承自ClassLoader,负责加载 D:ProgramFilesJavajdk1.8.0_261jrelibext
应用程序类加载器(系统类加载器)
Java编写,sun.misc.Launcher$AppClassLoader 实现,派生于 ClassLoader 类。 负责加载用户类
用户自定义类加载器
例如tomcat
Java 虚拟机对class文件采用的是按需加载的方式, 要该类时才会将它的class文件加载到内存中生成class对象。而且加载某个类的class文件时,Java 虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式.
工作原理:
- 如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请 求委托给父类的加载器去执行.如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器.如果父类加载器可以完成类的加载任务,就成功返回,倘若父类加载器无法完 成加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制.如果均加载失败,就会抛出 ClassNotFoundException 异常。
目的: 为了安全考虑 避免了用户自己写的类覆盖了系统中的类.
为什么要用到双亲委派机制?比如我们建一个java.lang包,里面class一个String类,我们加载类时,加载的是直接的类还是JDK的类呢?
那当然是不行的,如果可以运行,那么自己写的类将会替换掉JDK的String
双亲委派优点
- 安全,可避免用户自己编写的类动态替换 Java 的核心类,如 java.lang.String避免全限定命名的类重复加载(使用了 findLoadClass()判断当前类是否已加 载)
JVM 规定,每个类或者接口被首次主动使用时才对其进行初始化,有主动使用,自然就有被动使用.
主动使用:
- 通过new关键字被导致类的初始化访问类的静态变量、静态方法对某个类进行反射操作初始化子类,父类也会被初始化执行main方法
被动使用:
- 仅仅使用类的静态常量 而且是直接赋字面量的那种,比如
public final static int NUMBER = 5 ; //不会导致类初始化,被动使用
public final static int RANDOM = new Random().nextInt() ; //会导致类的初 始化,主动使用构造某个类的数组时不会导致该类的初始化
比如:Student[] students = new Student[10] ;
主动使用和被动使用的区别在于类是否会被初始化.
三、JVM 运行时数据区 运行时数据区的概念和组成JVM 的运行时数据区,不同虚拟机实现可能略微有所不同,但都会遵从Java 虚拟机规范,Java 8 虚拟机规范规定,Java 虚拟机所管理的内存将会包括以下几 个运行时数据区域: 程序计数器、java虚拟机栈、本地方法栈、java堆内存和方法区
Java 虚拟机定义了序运行期间会使用到的运行数据区,其中有一些会随着虚拟 机启动而创建,随着虚拟机退出而销毁.另外一些则是与线程一一对应的.这些与线程对应的区域会随着线程开始和结束而创建销毁
等待更新…
java虚拟机栈 本地方法栈 java堆内存 方法区


