一、什么是JVM
- JVM是Java Virtual Machine的简称;也就是我们常听说的java虚拟机。
- JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机
二、JVM的作用
概念:JVM就是模拟CPU执行指令的一个程序。
2.1 回顾我们之前的内容
jdk,jre,jvm这三者是的关系。
但是,jvm与操作系统的关系是什么样的。
可以看出,正是有了jvm的存在,有了JVM这个抽象层之后,Java就可以实现跨平台了。
三、jvm运行时的数据区域。
3.1 堆区(线程共享)
程序中创建的所有对象都存在堆里面。(数组也在堆里面)
jdk1.8 常量池也存在堆区
主要:堆里面还划分了两大区域:新生代和老年代。(主要用于垃圾回收是使用)
3.2 方法区(线程共享)
用来存储被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
注意:在jdk1.7 也叫永久代;jdk1.8 中也叫元空间。
3.3 jav虚拟机栈(线程私有)
Java 虚拟机栈的生命周期和线程相同:线程创建,就创建栈;线程销毁,就销毁线程对应的栈;
线程执行摸个方法就,就创建该方法栈,方法返回,就出栈。
用于保存局部变量表-----变量(=左边的);基础数据类型的值(=右边第基础数据类型,也在)。
3.4 本地方法栈
调用java语言就存放在,java虚拟机栈;调用别的语言的函数,就在本地方法栈。
3.5 程序计数器
用于表示程序的行号。
四、内存溢出(OOM)
运行时,除了程序计数器,其他都都可能发生OOM
4.1 OOM 与 内存泄漏
内存泄漏:线程生命周期太长,导致始终只用一些不常使用的数据(这些数据gc无法正常回收),随着时间越来越长,最终导致OOM;
4.2 OOM与StackOverflow
某个线程,调用方法,创建方法栈帧,入栈,如果栈中的栈帧超过jvm规定的数量,就会报这个异常。
五、类加载
- 加载 加载class字节码到java进程的内存中,在堆中创建类对象。
- 验证 验证java字节码是否符合规范。
- 准备 准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并 设 置类变量初始值的阶段。
- 解析 将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程
- 初始化 Java 虚拟机真正开始执行类中编写的 Java 程序代码,将主导权移交给应用程序。
来加载机制:jdk机制:双亲委派模型 其他机制:破坏双亲委派模型。
六、双亲委派模型
概念:遵循双亲委派机制的类加载,类加载不直接加载,认识委派给父类的加载器,以此类推,达到从上到下加载的方式。
- 启动类加载器
- 扩展类加载器
- 应用类加载器
- 自定义类加载器
6.1 优点
最大的优点就是安全了。
6.2 缺点
扩展性、灵活性没那么好;
比如:在叫jdbc中,jdk无法知道数据库驱动的类的类名。
解决方案:破坏双亲委派机制模型
常用的方案:SPI机制(由jdk提供一个ServiceLoaer.load,约定了jar包下的/META-INF/service/文件名) 中进行加载。
七、垃圾回收(gc)
在Java中,不用程序员自己分配内存,也不用去回收内存。这些事情都是由jvm自动回收垃圾功能来实现的。
我们首先要了解的是,那些区域需要回收内存。==》堆和方法区。
7.1如何判断一个对象是垃圾
1. 引用计数算法
给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;当引用失效时,计数器就-1;任何时刻计数器为0的对象就是不能再被使用的,即对象已"死"。
由于他无法有效解决循环引用的问题,所以java不使用这种算法。
2. 可达性分析算法
两个概念:GC Roots 及 引用链。
GC Roots:垃圾回收检查的结点
引用链:某个对象到GC Roots的路径。
垃圾:也就是不可达对象,如果一个对象到GC Roots是不可达,就是垃圾。
在这里,我们了解一下四种引用类型
1.强引用:普通的对象及=赋值 Object abj = new Object
gc永远不回收强引用的队象。
2.软引用 SoftReference<类型> xxx = new SoftReference(obj);
内存溢出时,会回收这部分队象。
3.弱引用
gc发生时,都会回收。
4.虚引用
无法使用时,只是gc,发起的一个通知。
7.2 垃圾回收算法
7.2.1 标记清除法
===> 老年代回收算法
分为两个步骤:标记和清除。
缺陷:1.效率,两个步骤的效率都不高。
2.清除后会产生大量的内存碎片。
7.2.2 复制算法
===> 新生代回收算法
"复制"算法是为了解决"标记-清理"的效率问题。
它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清除掉。
因为新生代具有朝生夕死的性质, 所以更适合这中算法。
缺陷 :利用率只有50%。
7.2.3 标记整理算法
===> 老年代回收算法
两个步骤:标记 和 整理
而是让所有存活对象都向一端移动,然后直接清理掉端边界以外的内存
7.2.4 分代回收算法
这个也是jvm中采取的算法。
没有具体的算法实现,只是不同的区域使用不同的垃圾回收策略。
---哪些对象会进入新生代?哪些对象会进入老年代?---
新生代:一般创建的对象都会进入新生代;
老年代:大对象和经历了 N 次(一般情况默认是 15 次)垃圾回收依然存活下来的对象会从新生代
移动到老年代
--什么时候发生gc?--
对象进入那个区域,哪个区域内存不足,哪个区域就触发该区域的gc。
两个GC:
1. Minor GC:又称为新生代GC,采取复制算法,效率高。
2. Major GC:又称为老年代GC,采取标记清除/标记整理算法;效率慢,一般是新生代的10倍以上。
八、垃圾回收器
8.1 几个概念
垃圾回收线程:
可以并行执行,但影虎线程可同时执行 ;也可能会暂停。
暂停:叫做STW(stop the world)
吞吐量: CPU执行用户代码的时间/CPU执行用户代码的时间+垃圾回收执行的时间;
就是程序性能的 指标;吞吐量越高,程序性能越好。
8.2 jvm中的垃圾回收器
1. Serial收集器(新生代收集器,串行GC)
新生代收集器(复制算法);单线程 ;不常用
2.ParNew收集器(新生代收集器,并行GC)
新生代收集器(复制算法);多线程
搭配CMS方案
3.Parallel Scavenge收集器(新生代收集器,并行GC)
新生代收集器(复制算法) ==》吞吐量优先;适用性能优先的程序。
4. Serial Old收集器(老年代收集器,串行GC)
老年代收集器(标记整理法);单线程
5. Parallel Old收集器(老年代收集器,并行GC)
老年代收集器(标记整理法)
吞吐量优先
所以在吞吐量优化的程序,只有一种选择。Parallel Old+Parallel Scavenge