JVM垃圾回收

GC的基本原理:将内存中不再被引用的对象进行回收,GC中用于回收的方法称为收集器。垃圾:不再被引用的对象。

对新生代的对象的收集称为minor GC;
对旧生代的对象的收集称为Full GC;
程序中主动调用System.gc()的GC为Full GC

如何判断可回收对象
1、引用计数算法
每当一个地方引用它时,计数器+1;引用失效时,计数器-1;计数值=0——不可能再被引用。

2、可达性分析算法:
向图,树图,把一系列“GC Roots”作为起始点,从节点向下搜索,路径称为引用链,当一个对象到GC Roots没有任何引用链相连,即不可达时,则证明此对象时不可用的。

注:在Java中可作为GCRoots的对象:
1)虚拟机栈(栈帧中的本地变量表)中引用的对象;
2)方法区中类静态属性引用的对象;
3)方法区中常量引用的对象;
4)本地方法栈中JNI引用的对象。

内存泄漏

内存泄露的原因:1)全局集合;2)缓存;3)ClassLoader
检查List,map等集合对象是否有使用完后,未清除的问题。List、Map等集合对象会始终存有对对象的引用,使得对象不能被GC回收
程序中保留着对永远不再使用的对象的引用。因此这些对象不会被GC回收,却一直占用内存空间却毫无用处。即:1)对象是可达的;2)对象是无用的。满足这两个条件即可判定为内存泄漏。
内存溢出
检查代码有否有死循环或者递归调用
检查是否有大循环重复产生新对象实体
检查数据库查询中,是否有一次获取全部数据的查询。一般来说,如果一次取十万条记录,就可能引起内存溢出。

垃圾回收算法
分代收集算法中堆空间被分为新生代和老年代。因为新生代中对象的存活率比较低,所以一般采用复制算法,老年代的存活率一般比较高,一般使用”标记-清理”或者”标记-整理”算法进行回收。

标记-清理算法

1.标记清除

标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。

在标记阶段首先通过根节点(GC Roots),标记所有从根节点开始的对象,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

在这里插入图片描述
适用场合:

存活对象较多的情况下比较高效
适用于年老代(即旧生代)
缺点:

容易产生内存碎片,再来一个比较大的对象时(典型情况:该对象的大小大于空闲表中的每一块儿大小但是小于其中两块儿的和),会提前触发垃圾回收
扫描了整个空间两次(第一次:标记存活对象;第二次:清除没有标记的对象)

2.复制算法

从根集合节点进行扫描,标记出所有的存活对象,并将这些存活的对象复制到一块儿新的内存(图中下边的那一块儿内存)上去,之后将原来的那一块儿内存(图中上边的那一块儿内存)全部回收掉
在这里插入图片描述
现在的商业虚拟机都采用这种收集算法来回收新生代。

适用场合:

存活对象较少的情况下比较高效
扫描了整个空间一次(标记存活对象并复制移动)
适用于年轻代(即新生代):基本上98%的对象是”朝生夕死”的,存活下来的会很少
缺点:

需要一块儿空的内存空间
需要复制移动对象

3.标记整理

复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。

这种情况在新生代经常发生,但是在老年代更常见的情况是大部分对象都是存活对象。如果依然使用复制算法,由于存活的对象较多,复制的成本也将很高。

在这里插入图片描述
标记-压缩算法是一种老年代的回收算法,它在标记-清除算法的基础上做了一些优化。

首先也需要从根节点开始对所有可达对象做一次标记,但之后,它并不简单地清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。这种方法既避免了碎片的产生,又不需要两块相同的内存空间,因此,其性价比比较高。

4.分代收集算法

分代收集算法就是目前虚拟机使用的回收算法,它解决了标记整理不适用于老年代的问题,将内存分为各个年代。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。

在不同年代使用不同的算法,从而使用最合适的算法,新生代存活率低,可以使用复制算法。而老年代对象存活率搞,没有额外空间对它进行分配担保,所以只能使用标记清除或者标记整理算法。
在这里插入图片描述

垃圾收集器

在这里插入图片描述
serial垃圾收集器
1.整个扫描和复制过程采用单线程的垃圾收集器,能与 CMS 收集器配合
2.“Stop The World”,它进⾏垃圾收集时,必须暂停其他所有的⼯作线程,直到它收集结束。
3.适用与单CPU,新生代空间较小及对暂停时间要求不高的应用,是client默认的GC方式。
4.可以通过-XX:+UseSerialGC来强制指定
在这里插入图片描述
ParNew收集器
1.并⾏的 多线程收集,能与 CMS 收集器配合
2.Stop The World
3.-XX: ParallelGCThreads 参数来限制垃圾收集的线程数
4.多线程操作存在上下⽂切换的问题,所以建议将-XX: ParallelGCThreads设置成和CPU核数相 同,如果设置太多的话就会产⽣上下⽂切换消耗
在这里插入图片描述
Parallel Scavenge收集器
1.并行回收收集器,又称“吞吐量优先”收集器。⽬标是达到 可控制的吞吐(Throughput)
2.并⾏的多线程收集器,使用复制算法的收集器
3.-XX:MaxGCPauseMillis参数GC停顿时间,500MB ——>300MB,这个参数配置太⼩的话会发生频繁GC
4.-XX:GCTimeRatio参数,99%
5.停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可用高效率地利用CPU时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

Serial old收集器
单线程的垃圾收集器,使⽤"标记–整理"算法
Parallel old收集器
Parallel Scavenge收集器的老年代版本,使⽤多线程+标记整理算法
CMS (Concurrent Mark Sweep)收集器
1.以获取最短回收停顿时间为⽬标的收集器
2.基于“标记-清除”算法实现的
3.可以使用-XX:+UseConeMarkSweepGC指定
3.步骤流程
初始标记(CMS initial mark) -----标记⼀下 GC Roots 能直接关联到的对象,速度很快
并发标记(CMS concurrent mark --------并发标记阶段就是进行 GC RootsTracing 的过程
重新标记(CMS remark) -----------为了修正并发标记期间因用户程序导致标记产⽣变动的标 记录
并发清除(CMS concurrent sweep)
4.CMS垃圾收集器缺点
1)CMS收集器对CPU资源非常敏感。CPU个数少于4个时,CMS对于用户程序的影响就可能变得很大,为了应付这种情况,虚拟机提供了一种称为“增量式并发收集器”的CMS收集器变种。

(2)CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致另一次Full GC的产生。在JDK1.5的默认设置下,CMS收集器当老年代使用了68%的空间后就会被激活。

(3)CMS是基于“标记-清除”算法实现的收集器,手机结束时会有大量空间碎片产生。空间碎片过多,可能会出现老年代还有很大空间剩余,但是无法找到足够大的连续空间来分配当前对象,不得不提前出发FullGC。在这里插入图片描述
G1收集器
G1收集器的优势:

独特的分代垃圾回收器,分代GC: 分代收集器, 同时兼顾年轻代和老年代
使用分区算法, 不要求eden, 年轻代或老年代的空间都连续(基于“标记⼀整理”算法实现为主和Region之间采⽤复制算法实现的垃圾收集)
并行性: 回收期间, 可由多个线程同时工作, 有效利用多核cpu资源
空间整理: 回收过程中, 会进行适当对象移动, 减少空间碎片
可预见性: G1可选取部分区域进行回收, 可以缩小回收范围, 减少全局停顿

G1收集器可以在几乎不牺牲吞吐量的前提下完成低停顿的内存回收,这是由于它能够极力避免全区域的垃圾收集,之前的收集器进行收集的范围都是整个新生代或老年代,而G1将整个Java堆(包括新生代、老年代)划分为多个大小固定的独立区域(Region),并且跟踪这些区域里面的垃圾堆积程度,在后台维护一个优先列表,每次根据允许的收集时间,优先回收垃圾最多的区域(这就是Garbage First名称的由来)。区域划分、有优先级的区域回收,保证了G1收集器在有限的时间内可以获得最高的收集效率。
3.步骤流程
初始标记(Initial Marking) --标记⼀下 GC Roots 能直接关联到的对象

并发标记(Concurrent Marking)—从GC Root 开始对堆中对象进⾏可达性分析,找出存活 的对象,这阶段耗时较长,但可与⽤户程序并发执行

最终标记(Final Marking) —为了了修正在并发标记期间因用户程序继续运作而导致标记产⽣生 变动的那⼀部分标记记录。每个 Region 都有⼀个与之对应的 Remembered Set,虚拟机将这段时间对象变化记录在线程 Remembered Set Logs ⾥面,最终标记阶段需要把 Remembered Set Logs的数据合并到 Remembered Set 中

筛选回收(Live Data Counting and Evacuation)
首先对各个Regin的回收价值和成本进行排序,根据用户所期待的GC停顿时间指定回收计划,回收一部分Region
4.通过-XX:G1HeapRegionSize指定分区大小
在这里插入图片描述

JVM垃圾收集器总结

本文主要介绍了JVM中的垃圾回收器,主要包括串行回收器、并行回收器以及CMS回收器、G1回收器。他们各自都有优缺点,通常来说你需要根据你的业务,进行基于垃圾回收器的性能测试,然后再做选择。下面给出配置回收器时,经常使用的参数:

-XX:+UseSerialGC:在新生代和老年代使用串行收集器

-XX:+UseParNewGC:在新生代使用并行收集器

-XX:+UseParallelGC :新生代使用并行回收收集器,更加关注吞吐量

-XX:+UseParallelOldGC:老年代使用并行回收收集器

-XX:ParallelGCThreads:设置用于垃圾回收的线程数

-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器

-XX:ParallelCMSThreads:设定CMS的线程数量

-XX:+UseG1GC:启用G1垃圾回收器

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值