JVM垃圾收集基础
基础知识
这里介绍的只是JVM垃圾收集的一些基础知识入门,后面会有文章展开讨论细节。
文章目录
为什么需要垃圾回收
我们现在的计算机中,内存是十分珍贵的,一般家用计算机也就8G左右,随着CPU的快速迭代,处理速度也越来越快,可以同时处理的任务也越来越多。但是内存需要存放程序代码,但是这个空间显然是有限的。即使有虚拟内存也是不够的。
所以现在的大部分的编程语言都会涉及的垃圾回收。但是每种语言的回收策略也是不同的。
C++:手工处理垃圾
缺点:也容易引起了一些问题,比如忘记回收造成内存泄露,多次回收造成的非法访问,而 且程序员开发效率低,很容易写出bug。
优点:执行效率高。
java:垃圾回收
缺点:执行效率低
优点:开发效率高,不同意引起上述问题。
垃圾收集基础
1.1 如何去判断是一个垃圾?
- 引用计数法: 会造成循环引用
- 根可达算法 :GC Roots(线程栈变量 静态变量 常量池 JNI指针)
1.2垃圾收集算法
- 标记清除 mark-sweep:1.实现简单,效率高 2.容易产生内存碎片 3.适合垃圾对象少的情况
- 复制算法 copy:1.适合存活对象较少的情况 2.没有内存碎片 3.空间浪费 4.需要调整对象引用地址
- 标记压缩 mark-compact:1.不会产生内存碎片 2.扫描2次,需要移动对象,效率低
1.3 JVM内存分代模型
新生代 (young)+ 老年代 (old) + 永久代(1.8以下)/元数据区(1.8开始)
- 新生代 : 复制算法(大部分对象存活时间较短),会触发MinorGC/YGC,设置大小:-Xmn
- 老年代: 标记清除(大部分对象存活时间较长),会触发MarjorGC/FullGC,设置大小:-Xms Xmx
G1:逻辑分代,物理不分代。
ZGC:没有使用这个内存分代模型
大部分GC都是这个内存分代模型
1.4 对象分配
- 栈上分配 1.小对象 2.无逃逸 3.标量替换
- 线程本地分配TALB 1.占用eden,默认1% 2.多线程避免竞争申请eden区域
- 老年代 1.大对象直接分配老年代
- 年轻代
默认开启:逃逸 标量替换 TALB
开启逃逸分析: (-XX:+DoEscapeAnalysis)
开启标量替换: (-XX:+EliminateAllocations)
TALB : -XX: +UseTLAB
1.5 对象何时进入老年代
- 超过 XX:MaxTenuringThreshold(控制对象经过GC多少次仍然存活后晋升到老年代的最大阈值),默认15
- 动态年龄 1.s1 -> s2超过50% ,年龄最大直接进入Old
- 分配担保:YGCsurvivor区空间不足,空间担保直接进入老年代。
1.6 常见的垃圾收集器
- Serial:单线程的,到达安全点(safe point)进行STW(用户线程全部停止),单CPU使用
- Parallel Scavenge:多线程的,也会造成STW,年轻代,吞吐量优先
- Parallel Old: 多线程的,也会造成STW,老年代
- ParNew: 多线程的,增强的Parallel Scavenge和配合CMS使用,响应时间优先,年轻代
- CMS:开启了并发回收的过程,但是问题较多。
垃圾收集器和内存大小关系?
Serial:几十兆
PS:上百兆-几个G
CMS:20G
G1:上百G
ZGC: 4T-16T
CMS
并发:工作线程和垃圾回收线程并发执行
过程:
- 1.初始标记(寻找gcroots)
- 2.并发标记(寻找垃圾对象) 占用大部分时间
- 3.重新标记(寻找并发阶段的产生的垃圾)
- 4.并发清理(会产生浮动垃圾)
问题:
- 浮动垃圾
- 碎片内存
- 并发回收造成的内存不足
cms问题:并发回收造成的内存不足
CMS垃圾回收报错(Concurrent Model Failure) 并发失败。
启动后备预案:冻结用户线程的执行,临时启用Serial Old收集器来重新进行老年代的垃圾收集。(这样的话时间就会变得很长)
解决:在JDK1.5之前老年带使用了68%空间后就会激活CMS收集。如果实际应用中可以适当调整参数-XX:CMSInitiatingOccu-pancyFraction 的值来提高CMS的触发百分比,降低内存回收频率获得更好的性能。
到了JDK6 CMS收集器的启动阀值就已经默认提升到92%。
三色标记:
1.颜色含义:
- 白色:未标记
- 灰色:自身标记,成员变量未标记
- 黑色:自身和成员变量标记
2.漏标
解决办法:
1.增量更新,关注引用增加 (CMS)
2.关注引用删除(B-D),把引用推到GC的堆栈 (G1使用RSet避免扫描整个堆)
G1
特点:
- 可预测的停顿时间–暂停时间特别短–200ms
- 较好的吞吐量(没有ps垃圾收集器好)
- 逻辑分代( Eden Survivor Old Humongous)
- Regin分区 2^n(最大32M)
- 压缩空间不会延长GC停顿时间
概念
- CSst(Collection Set) 一组可以被回收的分区集合
- RSet(RememberedSet)记录每个Region中对象到本Region引用
- 新生代老年代比例动态调整 5%-60%
GC触发
-
YGC
Eden空间不足触发
MixedGC:堆空间占用总空间45%,触发垃圾回收(相当于CMS) -
FGC
Old空间不足触发
java10以前是串行回收
优化:
- G1产生FGC如何优化?
1 增加内存 2.提高CPU性能,回收性能提升 3.降低MixedGC触发阈值,让MixedGC提早触发(45%)
多租户JVM
- 每租户单独空间
- session based GC