JVM(一)虚拟机基础
JVM 全称Java Virtual Machine,也就是我们耳熟能详的Java 虚拟机。它能识别.class 后缀的文件,并且能够解析它的指令,最终调用操作系统上的函数,完成我们想要的操作。
Java执行流程
当我们编写完程序之后文件就是.Java
文件通过Javac指令编译之后就是.class
文件,之后就是由JVM将类加载到方法区中,执行引擎执行这些字节码。
过程如下:Java 文件->编译器>字节码->JVM->机器码
。
JVM的跨平台、跨语言性
-
跨平台
Java官网提供了各个系统版本的JDK,我们根据系统下载对应版本的JDK就可以将我们写的类运行在不同的操作系统上。
官网直达:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
-
跨语言
因为JVM是通过识别字节码(.class文件)的方式进行运行的,所以只要其他语言如果也可以编译为字节码文件则也可以在JVM上运行,例如:Groovy、Kotlin等等一些语言。所以JVM也是一定程度上奠定了Java强大的生态圈。
JVM相关实现
JVM规范的存在提供了一些JVM的具体的实现。
-
Hotspot
使用最多的Java虚拟机,通过javac -version的命令可以看到。
-
Jrocket
原隶属于BEA公司,号称最快的JVM,后被Oracle所收购,与Hotspot所合并。
-
J9
IBM公司的JVM,主要用于自家产品上(IBM WebSphere 和IBM 的AIX 平台)。
-
TaobaoVM
淘宝根据HotSpot为自身定制的JVM,目前阿里、天猫都在使用。
-
zing
属于zual公司,很牛,但是很贵。它的垃圾回收速度非常快,之后它的垃圾回收算法被HotSpot所吸收形成了现在的ZGC。
JVM 整体知识模块
从下图中可以看到JVM的知识模块是比较多的,但是基本上都会与内存结构牵扯到一些关系,所以内存结构是非常重要的一块知识点。
JVM 内存区
class文件初始化时会将初始化的数据存放到方法区和堆中,当调用方法的时候会生成一个线程,线程中会虚拟出一块内存,通过执行引擎执行指令集,操作数据进行入栈出栈以及程序计数器计数,最后返回地址,从而完成一个方法的调用。
-
运行时数据区
-
线程共享区
-
方法区(规范,逻辑划分)
方法区是JVM中的一种规范。JDK 1.7 是以永久代实现方法区,JDK 1.8是以元空间实现方法区的,所以存在不同的叫法。此区域是在class加载的时候就已经将数据加载到方法区中了。
运行时常量池
:主要存放引用地址。即在类加载的时候会存在将符号替换为直接引用的一部,其实就是将对象 a = new 对象()转换为对象 a = 地址,其地址就是存放在运行时常量池的。 -
堆
用于存放对象的。
-
-
线程私有区
-
线程
此处每一个线程之间都是独立的、互不干扰的。每一个线程中都会存在三个大块—虚拟机栈、本地方法栈、程序计数器。
虚拟机栈
:主要核心为一个个栈帧,遵循栈的数据结构,先进后出。通过-Xss可以设置每个虚拟机栈的大小,一般默认为1MB(不同的操作系统默认设置的大小不一样)。每一个方法都会创建一个栈帧,直至方法执行结束则会出栈。 局部变量:主要存放八大基本数据类型以及对象的引用。
操作数栈:执行引擎的一个工作区,通过执行引擎执行指令集对数据进行入栈、出栈、计算等等。
动态连接:后期文章。
方法返回:将最终结果返回。
本地方法
:存放native所修饰的方法,因为这些方法都是由C/C++所实现的,可以通过此方法来操作系统。程序计数器
:单独划分的一块内存,主要存放当前执行引擎所执行的地址。因为多线程的情况所以需要记录当前线程所执行的地址/行号,类似于CPU时间片轮转,它的内部也存在一个类似程序计数器。 此区域是永远不会出现栈溢出异常。
-
-
-
直接内存
虚拟机内存以外的的内存,NIO可以操作此区域的内存。
UnSafe类也可以,Ehcache就是基于此类实现的,但不建议自己使用。