操作系统——垃圾回收

目录

一、垃圾回收定义

二、垃圾回收处理内存区域

三、垃圾标记

1、引用计数

(1)、定义

(2)、缺陷

2、可达性分析

(1)、定义

(2)、缺点 

四、垃圾回收过程

1、标记清除

(1)、定义

(2)、缺点

2、复制算法

(1)、定义

(2)、缺点

3、标记整理

(1)、定义

(2)、缺点

4、分代算法

(1)、定义

(2)、回收策略

五、垃圾回收器


一、垃圾回收定义

垃圾回收机制(GC)能够帮助程序员自动释放内存。Java等编程语言引入了GC来解决内存泄漏问题,通过JVM自动判断,能够有效的减少内存泄漏的出现概率。

二、垃圾回收处理内存区域

JVM中的内存有四个区域(堆区、栈区、元数据区、程序计数器),堆区是GC的主要目标,其余区域则不需要:

  • 栈会随着线程一起销毁,方法调用完毕后,方法的局部变量会随着出栈操作自动销毁
  • 元数据区存的是类对象,很少会卸载
  • 程序计数器是一个单纯存地址的整数,不需要处理,会随着线程一起销毁

三、垃圾标记

Java对于垃圾对象的识别较为保守,需要最大程度的避免误杀,释放不及时不太重要。一个对象如果后续再也不用,就可以认为是垃圾。Java中使用一个对象只能通过引用,而想要知道一个对象是否有引用指向,可以使用引用计数和可达性分析这两种方法来表明。

1、引用计数

(1)、定义

引用计数是给对象安排一个额外空间用来保存一个整数,表示该对象有几个引用指向。当引用增加时,计数器增加;引用销毁时,计数器减少;计数器为0时,则可认为没有引用,该对象就是垃圾

注:引用计数法实现简单,判定效率较高,Python、PHP等语言就采用引用计数法进行内存管理。但在主流的JVM中没有使用引用计数法来管理内存,最主要的原因就是引用计数法无法解决对象的循环引用问题。

(2)、缺陷

  • 浪费内存空间
  • 存在循环引用的情况,会导致引用计数的判定逻辑出错

当a和b销毁了,两个对象的引用计数各自减一。此时两个对象引用计数都是1,不能作为垃圾但是却不能使用,因此陷入了一个逻辑循环。

2、可达性分析

(1)、定义

可达性分析是把对象之间的引用关系理解成一个树型结构,从一些特殊的起点触发并进行遍历。能遍历访问到的对象就是可达,不可达的就是垃圾。

可达性分析进行上述遍历的起点:

  • 栈上的局部变量(每个栈的每个局部变量都是起点)
  • 常量池中引用的对象
  • 方法区中静态成员引用的对象

总的来说可达性分析就是从所有的的起点出发,查看该对象里通过引用能访问哪些对象,把所有可以访问的对象都遍历一遍,同时把对象标记成可达,剩下的就是不可达的垃圾。

(2)、缺点 

虽然可达性分析克服了引用计数的缺点但也存在问题:

  • 消耗更多时间:扫描过程中需要消耗时间,当某个对象成为垃圾时,不一定能第一时间发现
  • 需要暂停工作(STW问题):在进行可达性分析时需要让其他业务线程暂停工作,防止当前代码中的对象的引用关系发生变化

四、垃圾回收过程

1、标记清除

(1)、定义

标记清除算法是最基础的收集算法,算法分为“标记”和“清除”两个阶段:首先标记出所需回收的对象,然后在标记完成后统一回收所有被标记的对象。

(2)、缺点

  • 效率问题:标记和清除这过程的效率不高
  • 空间问题:标记清除后会产生大量不连续的内存碎片,申请空间都是申请的整块连续的空间,此处的空闲空间是离散的独立空间,因此虽然总的空闲空间充足但是无法申请到足够空间

2、复制算法

(1)、定义

复制算法是为了解决标记清理的效率问题,它将内存划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上,然后再把已经使用过的内存区域一次清理掉。每次都是对整个半区进行内存回收,内存分配时不需要考虑内存碎片等复杂情况,只需要移动堆顶指针按顺序分配即可,算法实现简单运行高效。

(2)、缺点

复制算法虽然解决了内存碎片的问题但也有缺点:

  • 内存利用率较低
  • 如果当前的对象大部分都是要保留——垃圾很少,此时复制成本就较高

3、标记整理

(1)、定义

标记整理算法的标记过程与标记清除过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动。这类似于顺序表删除中间元素,有一个搬运的过程,将不是垃圾的对象往前搬运,并把垃圾区域统一释放。

(2)、缺点

虽然解决了内存碎片问题,但是搬运开销较大。

4、分代算法

(1)、定义

分代算法和上述的三种算法不同,其是通过区域划分来实现不同区域和不同的垃圾回收策略,从而实现更好的垃圾回收。当前JVM垃圾收集都采用的是分代收集算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。

Java堆分为新生代和老年代:

  • 新生代:一般创建的对象都会进入新生代。在新生代中每次垃圾回收都有大批对象死去,只有少量存活,因此采用复制算法
  • 老年代:大对象和经历了 N 次(一般情况默认是 15 次)垃圾回收依然存活下来的对象会从新生代移动到老年代。而老年代中对象存活率高,没有额外空间对它进行分配担保,因此必须采用标记清理或标记整理算法

(2)、回收策略

给对象设定年龄概念,用来描述这个对象存在多久。如果一个对象刚诞生就认为是0岁。每经过一次可达性分析,如果没被标记成垃圾该对象就增加一岁。通过年龄来区分这个对象的存活时间。如果一个对象存活时间很长,它将继续存在更长的时间。

  • 新创建的对象放到伊甸区,当垃圾回收扫描到伊甸区后,绝大部分对象都会在第一轮GC中被清理,大多数对象都活不过一岁
  • 如果伊甸区的对象熬过第一轮GC,就可以通过复制算法拷贝到生存区。生存区分成大小均等的两半,一次只使用其中的一半。垃圾回收扫描一半的生存区对象,发现垃圾就淘汰,不是垃圾的通过复制算法,复制到生存区的另一半
  • 当这个对象在生存区熬过若干轮GC后,年龄增长到一定程度,就会通过复制算法拷贝到老年代
  • 进入老年代的对象年龄都很大,再消亡的概率比前面新生代对象小不少,针对老年代的GC的扫描频次会降低很多。如果老年代中发现某个对象是垃圾,就使用标记整理的方式清除
  • 特殊情况如果对象非常大,直接进入老年代(大对象直接使用复制算法)

五、垃圾回收器

  • Serial收集器:新生代收集器,串行GC
  • ParNew收集器:新生代收集器,并行GC
  • Parallel Scavenge收集器:新生代收集器,并行GC
  • Serial Old收集器:老年代收集器,串行GC
  • Parallel Old收集器:老年代收集器,并行GC
  • CMS收集器:老年代收集器,并发GC
  • G1收集器:唯一一款全区域的垃圾回收器
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值