垃圾回收机制|青训营笔记

67 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的第14天

垃圾回收机制:

垃圾回收是不定时的,回收的是堆中没有引用变量指向的数组或对象,这些就是垃圾,保存在堆中的变量没有作用域一说,即使运行到了超出使用该对象的作用域/代码块,它们在堆中占用的内存也不会被释放,等到没有引用变量指向它们的时候,才会变成垃圾,不能被使用,但仍然占着内存空间不放,在随后的一个不确定时间才会被垃圾回收器收走

回收对象:最通俗的讲就是堆中的对象没有引用变量指向该对象

严谨说法:回收死亡对象

如何判定对象死亡:
  1. 引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它时,计数器的值加1,当引用失效时,计数值就减1;任何时刻计数器为0的对象就是不可能再被使用的。引用计数算法实现简单,判定效率也高,大部分情况下是一个不错的算法,但是它很难解决对象之间相互循环引用的问题

  2. 可达性分析算法:通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为GC Roots引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

    object5和object6虽然相互引用,但是由于他们到GC Roots都不可达,因此会被判定为可回收的对象。

根据垃圾回收时候的不同需求产生的四种引用类别:
  1. 强引用:只要强引用还在,gc永远不会回收掉被引用的对象

    Object odj=new Object();
    
  2. 软引用:描述一些还有用但非必要的对象。在系统内存溢出前会把这些对象列入回收范围进行第二次回收(也就是说在系统将要内存溢出的时候才会对软引用对象回收),如果这次回收后还没有足够的内存,才会抛出内存溢出问题

  3. 弱引用:引用程度还要低于软引用,这些对象只能生存到下次gc工作之前。当gc工作时,无论内存是否足够都会将其回收(也就是只要gc工作就会将弱引用对象回收)

  4. 虚引用:一个对象是否存在虚引用,完全不会对其生存时间构成影响,也无法通过虚引用来获取一个对象实例,为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾回收器回收时收到一个系统通知

    虚引用只是用来得知对象是否被GC

垃圾回收过程:

1.用户线程创建的对象优先分配在Eden区,当Eden区空间不够时,会触发Minor GC。

Minor GC步骤: (1) 复制存活对象到Suvivor区另一块——>存活对象年龄+1 (2)清空Eden区和前一块Survivor区 (3)给需要创建的对象分配内存 异常情况:如果留空的S区空间不足存放GC后存活对象时,所有存活对象,通过分配担保机制,进入老年代。 2.垃圾回收结束后,用户线程又开始新创建对象并分配在Eden区,当Eden区空间不足时,重复上次的步骤进行Minor GC。 3.年老对象晋升到老年代 既然虚拟机采用分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应该放在新生代,哪些对象应该放在老年代中。 为了做到这点,虚拟机给每个对象定义了一个对象年龄(Age)计数器。如果对象在Eden出生并经过一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且把对象年龄设为1。对象在Survivor空间中每"熬过"一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将晋 升到老年代中。 4.Survivor空间不足,存活对象通过分配担保机制进入老年代。

6.垃圾回收算法

(1)标记-清除算法(Mark-Sweep算法) 此算法类似于类似本地文件夹内,先将要删除的文件标记- -下,之后遍历一个一个的删除。 分为两个阶段:标记、清除。 老年代的回收算法。 不足:效率不高,产生大量不完整的内存碎片(导致:在进入大对象,如果没有连续空间存放,触发Major GC)。

(2)复制算法(Copying算法) 此算法类似本地文件夹内,将要删除的文件全部复制到另一个文件夹,之后把前一个文件夹全删了。 新生代的回收算法。 内存使用率不高(50%)。 优点:实现简单、运行高效、不存在内存碎片问题。

(3)标记-整理算法(Mark-Compact算法) 老年代的回收算法。 两个阶段:标记、整理(移动存活对象到一端内存,清理另一端内存)。

(4)分代收集算法 在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。