参考:JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)html
1.什么是jvm?
(1)jvm是一种用于计算设备的规范,它是一个虚构出来的机器,是经过在实际的计算机上仿真模拟各类功能实现的。
(2)jvm包含一套字节码指令集,一组寄存器,一个栈,一个垃圾回收堆和一个存储方法域。
(3)JVM屏蔽了与具体操做系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就能够在多种平台上不加修改地运行。
JVM在执行字节码时,实际上最终仍是把字节码解释成具体平台上的机器指令执行。java
2.jdk、jre、jvm是什么关系?
(1)JRE(Java Runtime Environment),也就是java平台。全部的java程序都要在JRE环境下才能运行。
(2)JDK(Java Development Kit),是开发者用来编译、调试程序用的开发包。JDK也是JAVA程序须要在JRE上运行。
(3)JVM(Java Virtual Machine),是JRE的一部分。它是一个虚构出来的计算机,是经过在实际的计算机上仿真模拟各类计算机功能来实现的。
JVM有本身完善的硬件架构,如处理器、堆栈、寄存器等,还具备相应的指令系统。
Java语言最重要的特色就是跨平台运行。使用JVM就是为了支持与操做系统无关,实现跨平台。面试
3.JVM原理
(1)jvm是java的核心和基础,在java编译器和os平台之间的虚拟处理器,可在上面执行字节码程序。
(2)java编译器只要面向jvm,生成jvm能理解的字节码文件。java源文件经编译成字节码程序,经过jvm将每条指令翻译成不一样的机器码
,经过特定平台运行。(JIT即时编译器Just-In-Time Compiler)算法
4. JVM执行程序的过程
1) 加载.class文件 具体参考:Java 类加载机制(阿里面试题)数组
2) 管理并分配内存
3) 执行垃圾收集
JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,可是他同时一个操做系统的一个应用程序一个进程,
所以他也有他本身的运行的生命周期,也有本身的代码和数据空间。
JVM在整个jdk中处于最底层,负责于操做系统的交互,用来屏蔽操做系统环境,
提供一个完整的Java运行环境,所以也就虚拟计算机。
操做系统装入JVM是经过jdk中Java.exe来完成,
经过下面4步来完成JVM环境:
1) 建立JVM装载环境和配置
2) 装载JVM.dll
3) 初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例
4) 调用JNIEnv实例装载并处理class类。
5. JVM的生命周期
1) JVM实例对应了一个独立运行的java程序它是进程级别
a) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void
main(String[] args)函数的class均可以做为JVM实例运行的起点
b) 运行。main()做为该程序初始线程的起点,任何其余线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程一般由JVM本身使用,java程序也能够代表本身建立的线程是守护线程
c) 消亡。当程序中的全部非守护线程都终止时,JVM才退出;若安全管理器容许,程序也可使用Runtime类或者System.exit()来退出
2) JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的安全
六、JVM内存模型markdown
(1)java代码具体执行过程以下图,多线程
(2)运行时数据区,即jvm内存结构图以下图架构
(3)运行时数据区存储了哪些数据?jvm
a) 程序计数器(PC寄存器)
因为在JVM中,多线程是经过线程轮流切换来得到CPU执行时间的,所以,在任一具体时刻,一个CPU的内核只会执行一条线程中的指令,
所以,为了可以使得每一个线程都在线程切换后可以恢复在切换以前的程序执行位置,每一个线程都须要有本身独立的程序计数器,而且不能互相被干扰,
不然就会影响到程序的正常执行次序。所以,能够这么说,程序计数器是每一个线程所私有的。因为程序计数器中存储的数据所占空间的大小不会随程序的执行而发生改变,
所以,对于程序计数器是不会发生内存溢出现象(OutOfMemory)的。
b) java栈
Java栈中存放的是一个个的栈帧,每一个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、操做数栈(Operand Stack)、
指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、
方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之建立一个对应的栈帧,并将创建的栈帧压栈。当方法执行完毕以后,便会将栈帧出栈。
c)本地方法栈
本地方法栈与Java栈的做用和原理很是类似。区别只不过是Java栈是为执行Java方法服务的,而本地方法栈则是为执行本地方法(Native Method)服务的
d)堆
Java中的堆是用来存储对象自己的以及数组(数组引用是存放在Java栈中的)。堆是被全部线程共享的,在JVM中只有一个堆。
e)方法区
与堆同样,是被线程共享的区域。在方法区中,存储了每一个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。
在方法区中有一个很是重要的部分就是运行时常量池,它是每个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,
对应的运行时常量池就被建立出来。固然并不是Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,好比String的intern方法。
七、JVM内存溢出的状况
a) 程序计数器(Program Counter Register)
每条线程都有一个独立的的程序计数器,各线程间的计数器互不影响,所以该区域是线程私有的。该内存区域是惟一一个在Java虚拟机规范中没有规定任何OOM(内存溢出:OutOfMemoryError)状况的区域。
b)Java虚拟机栈(Java Virtual Machine Stacks)
在Java虚拟机规范中,对这个区域规定了两种异常状况:
一、若是线程请求的栈深度大于虚拟机所容许的深度,将抛出StackOverflowError异常。
二、若是虚拟机在动态扩展栈时没法申请到足够的内存空间,则抛出OutOfMemoryError异常。
这两种状况存在着一些互相重叠的地方:当栈空间没法继续分配时,究竟是内存过小,仍是已使用的栈空间太大,其本质上只是对同一件事情的两种描述而已。
在单线程的操做中,不管是因为栈帧太大,仍是虚拟机栈空间过小,当栈空间没法分配时,虚拟机抛出的都是StackOverflowError异常,而不会获得OutOfMemoryError异常。
而在多线程环境下,则会抛出OutOfMemoryError异常。
c)堆Java Heap
Java Heap是Java虚拟机所管理的内存中最大的一块,它是全部线程共享的一块内存区域。几乎全部的对象实例和数组都在这里分配内存。Java Heap是垃圾收集器管理的主要区域,所以不少时候也被称为“GC堆”。
根据Java虚拟机规范的规定,Java堆能够处在物理上不连续的内存空间中,只要逻辑上是连续的便可。若是在堆中没有内存可分配时,而且堆也没法扩展时,将会抛出OutOfMemoryError异常。
d)方法区域,又被称为“永久代”,当方法区没法知足内存分配需求时,将抛出OutOfMemoryError异常。
关于垃圾回收算法
(1)目前根据 Mark-Sweep算法 延伸出来了CMS算法(concurrent Mark-Sweep)算法
(2) G1(Garbage First)算法
这两个阿里的面试官问过他们的区别:
我作了整理:
参考:JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)
参考:G1 垃圾收集器入门
参考:jvm内存模型和内存分配