文章目录
- 为什么学习JVM?
- 什么是虚拟机?
- JVM的作用
- JVM组成部分
- 类加载器
- 类什么时候会被加载(初始化)
- 有哪些类加载器
- 什么是双亲委派机制
- 如何打破双亲委派机制
为什么学习JVM?
学习JVM是为了能更深入的理解Java这门语言,理解Java语言底层的执行过程,为后期写出优质代码做好准备。
很多时候一个问题需要深入到字节码层次去分析才能得到准确的结论,而字节码就是JVM的一部分。并且以后项目上线去排查一些程序log日志中无法呈现的问题,如:内存溢出,GC太频繁导致高延迟问题
对于Java程序员来说,在虚拟机内存管理机制下,不需要像C/C++语言那样手动去垃圾回收操作,不容易出现内存泄漏和内存溢出等问题。但正是因为Java程序员吧内存控制权交给Java虚拟机,一旦出现内存方面泄露和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会非常艰难。
什么是虚拟机?
虚拟机就是一个虚拟的计算机,相当于一款软件,用来执行一系列虚拟的计算机指令,虚拟机分为 系统虚拟机(VMware)和程序虚拟机(JVM)。
JVM就是Java虚拟机,是一种执行Java字节码文件的虚拟计算机(最终解释为机械执行),拥有独立的运行机制。Java虚拟机是Java技术的核心,所有的Java程序都运行在Java虚拟机的内部。
JVM的作用
总的来说,JVM就是运行Java字节码的虚拟机,运行并管理Java源码文件所生成的
.class
文件;JVM负责装载字节码到其内部,编译为对应平台上的机械码指令执行。 特点: 一次编译到处执行,自动内存管理,自动垃圾回收功能。
现在的 JVM 不仅可以执行 java 字节码文件,还可以执行其他语言编译后的字节码文件,是一 个跨语言平台.
JVM组成部分
JVM主要是由类加载器,运行时数据区,执行引擎,本地方法接口,垃圾回收组成
-
程序在执行前先要把Java代码转换成字节码(class文件)文件,JVM需要把字节码通过一定方式的类加载器(ClassLoader) 把文件加载到内存的运行时数据区(Runtime Data Area),而字节码文件是JVM的一套指令集规范,并不能直接由底层操作系统区执行,因此需要特定的命令解析器执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交给CPU去执行,这个过程中需要调用其他语言的接口 本地库接口(Native Interface) 来实现整个程序的功能。
-
通常需要程序员调试分析的区域就是”运行时数据区“,具体一点就是”运行时数据区“里面的Heap(堆)模块。
类加载器
作用: 负责从硬盘/网络中加载字节码信息到内存中(运行时数据区的方法区中)
类加载过程:主要分为加载、链接、初始化,链接部分分为验证、准备、解析
加载: 使用IO读取字节码文件,转换并存储,为每个类创建一个class类的对象并存储载方法区中
链接:
验证:检查被加载的类的内部结构是否正确,并对字节码文件的格式进行 验证,然后判断文件是否被污染并对基本的语法格式进行验证,如果都验证通过就会进入准备阶段。
准备:为静态的变量进行内存分配,并设置默认初始值,不包含用
final
修饰的static
常量解析:将符号引用转为直接引用,将字节码中的表现形式转为内存中的表现形式
初始化: 类的初始化,为类中的定义的静态变量进行赋值
类什么时候会被加载(初始化)
JVM规定,每个类或者接口被首次主动使用时才对其进行初始化
1.在类中运行main方法
2.创建对象
3.使用类中的静态变量,静态方法
4.反射 Class.forName(“类的地址”);
5.子类被加载
有两种情况类不会被初始化:
- static final int b = 20; 编译期间赋值的静态常量
- System.out.println(User.b);
- User[] users = new User[10]; 作为数组类型
有哪些类加载器
主要有三个类加载器,引导类加载器,扩展类加载器,应用程序类加载器,其中扩展类加载器和应用程序类加载器都属自定义类加载器(只要继承了
ClassLoader
类的都属于自定义类加载器)。
引导类加载器是用C/C++语言还发的,JVM底层的开发语言,负责加载Java核心类库。
扩展类加载器是从JDK系统安装目录的
jre/lib/ext
子目录下下载类库。
应用程序类加载器用户加载程序中自己开发的类
什么是双亲委派机制
如果一个类加载器收到了类加载请求,它并不会自己先去加载,二十把这个请求委托给父类的加载器去执行,如果父加载器还存在其父加载器,则继续向上委托,最终将到达顶层的启动类加载器,如果父类加载器可以完成类的加载任务,就成功返回,若无法完成加载任务,子加载器才会尝试自己去加载。如果都加载失败,则抛出异常ClassNotFoundException。
目的:为了先确保加载系统类
优点:安全,可以避免用户自己编写的类替换Java的核心类库,并避免类重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
如何打破双亲委派机制
可以通过继承ClassLoader类,重写loadClass/findClass方法,实现自定义的类加载
典型的tomcat中,加载部署在tomcat中的项目时,就使用的是自己的类加载器