JVM 知识整理
一,jvm 基础知识
Java 是一种面向对象的、静态类型、编译执行,有 vm/GC 和运行时、跨平台的高级语言。
字节码、类加载器、虚拟机内存
jvm 通过类加载器加载字节码到虚拟机内存
类加载器
启动类加载器
jvm 最核心的 jar 包和类,比如 String 和 Object,它是所有应用程序都需要使用的类
扩展类加载器
负责给 jvm 加载一些额外的类,比如我们在目录里额外放一些 jar 包
应用类加载器
负责加载我们自己的代码生成的类以及依赖项
为什么要有这个区分
1、双亲委托
2、负责依赖
3、缓存加载
jvm 内存模型
方法中使用的原生数据类型和对象引用地址在栈上存储
对象、对象成员与类定义、静态变量在堆上
堆内存又称为"共享堆",堆中的所有对象,可以被所有线程访问,只要
他们能拿到对象的引用地址
如果两个线程同时调用某个对象的同一方法,则它们都可以访问到这个对象的成员变量,
但每个线程的局部变量副本是独立的
jvm 启动参数
1 系统属性参数
2 运行模式参数
3 堆内存设置参数
4 GC 设置参数
5 分析诊断参数
6 JavaAgen 参数
GC 背景与一般原理
为什么会有 GC
本质上是内存资源的有限性
因此需要大家共享使用,手工申请,手动释放
如果你自己去设计对象回收机制怎么设计
通过一个仓库的例子
有人使用就+1,不用了就登出
实际情况复杂一点
仓库与仓库之间也有关系
如果是一个环的话,大家的计数永远不为 0,会导致内存泄漏-》内存溢出
这个地方跟事务的死锁是一个道理
改进:引用计数-〉引用跟踪
那既然采用了引用跟踪,我们就要想它有什么算法 -》标记清除算法,它是并行 GC 和 CMS GC 的基本原理
标记:遍历所有的可达对象,并在本地内存中分门别类记下
清除:这一步保证了,不可达对象所占用的内存,在之后进行内存分配时可以重用
它的优势就是对于饮用计数的循环依赖问题是可以解决的,因为它只跟踪可达的对象,就算形成了一个环,但是如果都是不可达的,那么在引用跟踪也会清除
除了清除还要做压缩,就是碎片整理
怎么才能标记和清除上百万对象,答案就是 STW,让全世界停下来
怎么理解 STW,就是一个阿姨打扫屋子的案例,很多人在屋子里走来走去,要打扫屋子了,就让他们先出去
对象分配在新生的 Eden 区域
标记阶段 Eden 区存活的对象就会复制到存活区
注意:为什么是复制,不是移动
两个存活区 from 和 to,互换角色。
对象存活到一定周期会提升到老年代
由参数控制提升阈值
老年代默认都是存活对象,采用移动方式
1.标记所有通过 GC roots 可达的对象
2 删除所有不可达对象
3 整理老年代空间中的内容,方法是将所有的存活对象复制,从老年代空间
开始的地方依次存放
新生代
发生 minor gc 时,用的是标记复制算法
java 新生代为什么要有两个 survivor 区
1)survivior 存在的意义就是做一个预筛选,减少被送到老年代的对象,进而减少 FULLGC 的发生
2)设置两个 survivor 区最大的好处就是解决了碎片化
串行 GC
Serial GC
并行 GC
Parallel GC
jdk6,7,8 默认都是并行 GC,再之上的版本 9 以后都是 G1
CMS GC
设置目标是避免在老年代垃圾收集时出现长时间的卡顿
还是阿姨打扫房间的例子,并行 GC 就是先让人出去,多个阿姨打扫房间。
CMS GC 就是先不用出去,让出 1/4 的空间,我们一块儿一块儿的打扫
六个阶段
1)初始标记
2)并发标记
3)并发预清理
4)最终标记
5)并发清除
6)并发重置
重置 CMS 算法相关的内部数据,为下一次 GC 循环做准备
CMS 优缺点
最大的问题就是老年代内存碎片问题
G1 GC
G1 GC 最主要的设计目标是:将 STW 停顿的时间和分布,变成预期且可配置的
G1 GC 堆不再分成年轻代和老年代,而是划分为多个小块,每个小块可能一会被定义成 Eden 区,
一会被指定为 Survivor 区域、或者 Old 区
ZGC
java11 引入
Shenandoah GC
java12 引入
评论