JVM 深入理解(一)
2020-06-13 本文已影响0人
only_one
简介:
Java Virtual Machine JVM 全称 Java Virtual Machine,也就是我们耳熟能详的 Java 虚拟机。它能识别 .class后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。
翻译:Java 程序不一样,使用 javac 编译成 .class 文件之后,还需要使用 Java 命令去主动执行它,操作系统并不认识这些 .class 文件。所以JVM就是一个翻译。
image.png从图中可以看到,有了 JVM 这个抽象层之后,Java 就可以实现跨平台了。JVM 只需要保证能够正确执行 .class 文件,就可以运行在诸如 Linux、Windows、MacOS 等平台上了,JVM讲.class和.jar进行翻译成操作系统能识别的机器码,从而调用操作系统的方法。
JVM、JDK,JRE之间的关系:
JVM:只是一个翻译,把Class翻译成机器识别的代码,JVM 不会自己生成代码,需要大家编写代码,同时需要很多依赖类库,这个时候就需要用到JRE。(翻译)
JRE:它除了包含JVM之外,提供了很多的类库(就是我们说的jar包,它可以提供一些即插即用的功能,比如读取或者操作文件,连接网络,使用I/O等等之类的)这些东西就是JRE提供的基础类库。JVM 标准加上实现的一大堆基础类库,就组成了 Java 的运行时环境,也就是我们常说的 JRE(Java Runtime Environment)。(提供类库)
JDK:提供了一些非常好用的小工具,比如 javac(编译代码)、java、jar (打包代码)、javap(反编译<反汇编>)等。这个就是JDK(提供工具)
JVM整体流程图:
流程图.png图中的运行时数据区:jvm所管理的内存。
执行引擎:将放在运行时数据区的中的方法,和操作进行解释执行。
解释执行与JIT之间的区别:
以HelloWord.java为例,通过javac进行编译之后得到.class文件,通过ClassLoader进行类加载到运行时数据区中(jvm所管理的内存),jvm再通过执行引擎将运行时数据区中的数据进行翻译机器码,从而执行调用操作系统的方法。那么还是没有说到解释执行和JIT 呢?
翻译:
(1)、将所有的类都全部翻译成机器码之后才执行,(速度慢,效率低)
(2)、一遍翻译一遍执行,(相比第一种速度上有了很大的提升)-----解释执行。
那什么又是JIT呢?
在hotspot中,可能会有热点方法,如我们同一个方法执行很多次,jvm会将这部分代码直接编程成本地代码,提高运行速度,(前提是热点方法,热点类)
运行时数据区:
运行时数据区的定义:
Java虚拟机在执行Java程序 的过程中会把它所管理的内 存划分为若干个不同的数据 区域。
运行时数据区的类型:程序计数器、虚拟机栈、本 地方法栈、Java堆、方法区 (运行时常量池)、直接内存。
如图所示:
image.png1、程序计数器:当前线程执行的字节码的行号指示器;各线程之间独立存储,互不影响。
举个例子:现有一个Person类,Person中提供了对应的方法,通过javac编译之后得到对应的.class文件,现在通过javap -c 对.class 文件进行反编译,如图所示:
image.png上图所示是通过反编译得到.class文件的对应的字节码,每行都有对应的编号,在多线程中,cpu调度线程的,时间轮转时线程通过程序计数器记录当前的对应的行号,直到线程下次拥有cpu调度时接着执行,从而确保程序的正常执行。
2、虚拟机栈:存储当前线程运行方法所需的数据,指令,返回地址,栈(先进后出)
2.1、栈帧(方法)
2.1.1、局部变量表:用来存储局部变量 只能 存储8大基本类型,对象引用
2.1.2、操作数栈:存放方法的操作、执行。
2.1.3、动态链表::Java语言特性多态(需要类运行时才能确定具体的方法)。
2.1.4、完成出口:正常返回(调用程序计数器中的地址作为返回)、异常的话(通过异常处理器表<非栈帧中的>来确定)
3、方法区:
方法区主要存储:类信息,常量,静态变量,即时编译期编译后的代码。
4、堆:
堆主要存储:几乎所有对象实例,数组。
方法区和堆为啥不用一个区域,要用两个区域?堆可以进行频繁的回收,方法区回收比较难,动静分明。
从底层深入理解运行时数据区:
image.png1、申请内存,分别给堆,栈,方法区分配内存。
2、类加载,class进入方法区。
3、常量,静态变量 入方法区。
4、虚拟机栈帧--入栈帧
下面先介绍一下HSDB工具,查看内存的工具:
1)、首先找到jdk的安装目录,找到sawindbg.dll文件,将改文件复制到对应目录的jre下。
image.png2)、现在采用JVMObject.java为例:
public class JVMObject {
public final static String MAN_TYPE = "man"; // 常量
public static String WOMAN_TYPE = "woman"; // 静态变量
public static void main(String[] args)throws Exception {//栈帧
Teacher T1 = new Teacher();//堆中 T1 是局部变量
T1.setName("Mark");
T1.setSexType(MAN_TYPE);
T1.setAge(36);
for (int i=0;i<15;i++){//进行15次垃圾回收
System.gc();//垃圾回收
}
Teacher T2 = new Teacher();
T2.setName("King");
T2.setSexType(MAN_TYPE);
T2.setAge(18);
Thread.sleep(Integer.MAX_VALUE);//线程休眠很久很久
}
}
class Teacher{
String name;
String sexType;
int age;//堆
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSexType() {
return sexType;
}
public void setSexType(String sexType) {
this.sexType = sexType;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}