面试准备每日系列:计算机底层之并发编程(三)JVM-垃圾回收

1. 什么是垃圾

new出来 最后不用了并且没有被回收的那块内存 就是垃圾;

C、C++让用户自己回收,java、python、js等带有垃圾收集器,Golang也有(仍STW);

C: malloc free
C++:new delete

new出来内存不及时回收就会导致内存泄漏,泄露多了就会容易造成内存溢出;

不用管回收,又没有垃圾回收器帮我回收,没有严重停顿——只有 Rust;

把钱放在一边,不功利性地学习,钱就来了

垃圾:一个对象没有引用指向它,那它就是垃圾;

2. 检测/识别垃圾

引用计数法(Reference Count)

但 RC 解决不了循环引用的问题:
在这里插入图片描述

根可达算法(Root Searching)

对于对象树这种处理得尤为巧妙,从根开始找,寻得到的都是有用的,寻不到的都是垃圾,不管你循环引用还是啥;

❗哪些是根对象?

大厂常问
在这里插入图片描述

3. 垃圾回收算法

标记清除法(Mark-Sweep)

在这里插入图片描述
缺点:容易 碎片化,效率偏低;

拷贝法(Copying)

在这里插入图片描述
内存一分为二,下半部分不给new,需要垃圾回收的时候,把上半部分活着的对象复制到下半部分,然后把上半部分全部清理;

没有碎片;
缺点:浪费空间;

当存活对象很多时,copying就要复制一大堆对象,效率降低;所以比较适合存活对象少,垃圾多的场景;

标记压缩法(Mark-Compact)

在这里插入图片描述
边释放边整理(把有用的挪到一起)

没有碎片;
缺点:效率低;

当垃圾很多时,MC 算法就要进行很多次 清理-移动操作,效率降低,所以它比较适合 存活对象多、垃圾少的场景

❗JVM内存分代模型(分代垃圾回收算法)

JDK 从1.0到14.0 所用到的十种垃圾回收器;
在这里插入图片描述
JVM 内存模型归 GC 来管;

堆内存逻辑分区:
在这里插入图片描述

年轻代:常常大量产生、大量回收对象;所以很多垃圾,就把幸存者 复制 到survivor1 区,然后把 eden 全部清空;

为什么年轻代用 copying 算法
  就是因其在 存活对象少、垃圾多时 回收效率较高,但考虑到 copying算法 1:1的内存划分代价太大,所以新生代内存被划分了 大块eden 和 两个小块 survivor ;;每次使用 eden 和 其中一块 survivor;(HotSpot虚拟机默认其比例为 8:1:1 )

为什么要设两个 survivor 区?
  如果只有一个 survivor 区,当第一次把 eden 的幸存者复制到 survivor 时,假设有四个对象,在下一次 GC 时,怎么执行copying 算法把 survivor 里面的垃圾干掉,所以就需要另一个 survivor 区,把 survivor 和 eden 的幸存者复制过去,清空它门;然后交换两个 survivor区,循环使用;

年轻代循环:

eden中产生对象,把幸存者复制到survivor1区,清空eden区;
while( true )
{
	eden产生对象,把幸存者和survivor1区幸存者复制到survivor2区,清空eden和survivor1区;
	if( age>=15 || survivor2区==full )
	{
		将该幸存者复制到老年代;
	}
	此时survivor1区空,survivor1区和survivor2区角色交换(即1区变2区,2区变1区);
	所有幸存者年龄+1;
}

老年代因为幸存者多、垃圾少,所以更适合 MC 标记压缩算法;
年轻代效率更改,更频繁;

学东西,先学脉络,再学细节!

总结:
在这里插入图片描述
调优最先知道的就是 用的哪种垃圾回收器;
jdk > 1.8以上的 建议用 G11.8默认Parallel Scavenge & Parallel Old

Serial

A stop-the-world(STW),copying collector which uses a single GC thread;
一堆小朋友(线程)在家里(堆)玩,家长(回收器)进来,说你们站一边去(STW),然后她就打扫屋里的垃圾,打扫完之后,告诉小朋友,好了你们可以继续玩了;

Parallel Scavenge

A stop-the-world,copying collector which uses multiple GC threads;
之前屋子面积(内存)小,一个人就够了,现在面积大了,一个人不够用了,需要多派几个人打扫;
垃圾回收器随着内存增大而演进;

Serial Old

采用标志收集算法的 serial 而已,针对老年代;

Parallel Old

采用标志收集算法的 Parallel 而已,针对老年代;

ParNew

PN≈PS
有点增强使之能配合 CMS

❗STW缺陷

STW 时期长的有一天以上的,主要服务器不能重启,很麻烦;

CMS

concurrent mark sweep
a mostly concurrent,low-pause collector;
分四个阶段

  • 初始标记:找到根节点 GC roots,需要STW;
  • 并发标记:进行GC Roots Tracing;
  • 重复标记:统计每个对象存活信息,进行修正,需要STW;
  • 并发清除:用标记清理算法清理;

优点:

  • 大部分时间可与用户线程并发工作
  • 低停顿

缺点:

  • 产生内存碎片;此时,若来一个大对象,没空间它就会用 Serial Old 进行清理(即一个人打扫大屋子);为啥不用 PO ?只有开发者知道;

并发标记算法
三色标记
在这里插入图片描述
发生错标的情况:
在这里插入图片描述
D 其实不是垃圾,但会当成垃圾处理掉,因为它是白色
白色的 表示 没标到的 都是垃圾;

为什么A指向D后,不把D变色,因为A已经是黑色,它不会检查自己的孩子了;

ems 阶段三 重新标记就会从头扫一遍,但由于有缓存,没有初始扫描时间长,用来修正;

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值