垃圾回收机制

Posted 玹之又玹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾回收机制相关的知识,希望对你有一定的参考价值。

1.垃圾回收

1.1 概述

      有些语言不支持垃圾自动回收,需要手动回收,而java是支持自动垃圾回收的,但是垃圾回收不是java语言首创的,垃圾回收关系的问题:那些区域需要回收,什么时候回收,如何回收。java的自动回收经过长时间的发展,已经非常强大了。

1.2 什么样的对象是垃圾

      在运行过程中,没有被任何引用指向的对象,被称为垃圾对象。

1.3 为什么需要GC

如果不及时清理这些垃圾对象,会导致内存溢出。在回收时,还可以将内存碎片进行整理。(例如数组必须是连续空间存储)

1.4 内存溢出和内存泄漏

       内存溢出:经过垃圾回收后,内存中仍然无法创建新的对象,内存不够用溢出。

       内存泄漏:例如IO流没有close。JDBC连接运行结束后没有colse关闭,或是是生命周期很长的对象,一些经常不用的对象,但是垃圾回收器不能判断为垃圾,这些对象就默默的占用着内存,称为内存泄漏,大量的此类对象存在会导致出现内存溢出,也就是导致内存溢出的原因。

1.5 自动内存管理

好处:解放程序员,对内存管理更加合理,自动化。

缺点:对程序员管理内存的能力降低了,解决问题能力变弱了,不能调整垃圾回收的机制。

2.垃圾回收相关算法

2.1 标记阶段

作用:判断对象是否是垃圾对象,是否有引用指向对象。

          相关的标记算法:引用计数算法可达性分析算法

2.2 引用计数算法

引用计数算法(在现代的jvm中并没有使用)实现原理是有个计数器来记录对象的引用数量

String s1 = new String("aaa");
String s2 = s1;  //此时“aaa”这个对象有两个引用变量指向它,计数器值为2
s2 = null; -1
s1 = null; -1

缺点:需要维护计数器,占用空间,频繁操作需要事件开销。无法解决循环引用问题,多个对象之间相互引用,没有其他外部引用指向他们,计数器都不为0,不能回收,产生内存泄漏。

2.3可达性分析算法/根搜索算法

实现思路:从一些为根对象(GCRoots)的对象出发去查找,与根对象直接或者间接连接的对象就是存活的对象,不与根对象引用链连接的对象就是垃圾对象。

 

2.4 GC Roots可以是那些元素?

1.在虚拟机栈中被使用的。

2.在方法中存储的静态成员变量指向的对象

3.作为同步锁使用的 Synchronized

4.在虚拟机内部使用的对象

2.5 对象放finalization机制

当一个对象被标记为垃圾后,在真正被回收之前,会调用一次Object类中的finalize(),是否还有逻辑需要进行处理。自己不要调用finalize(),留给垃圾回收器调用。

有了finalization机制的存在,在虚拟机中把对象状态分为三种:

1.可触及的: 不是垃圾,与根对象连接的对象状态。

2.可复活的:判定为垃圾了,但是还没有调用finalize(),(在finalize()中对象可能被别的引用变量指向,从而再次复活);

3.不可触及的:判定为垃圾了,且finalize()方法也已经被执行过了,这种就是必须被回收的对象。

2.6 垃圾回收阶段算法

标记--复制算法:

将内存分为大小相等的两份空间, 把当前使用的空间中存活的对象 复制到另一个空间中, 将正在使用的空间中垃圾对象清除.

优点: 减少内存碎片

缺点: 如果需要复制的对象数量多,效率低.

适用场景: 存活对象少 新生代适合使用标记复制算法

标记-清除算法

清除不是真正的把垃圾对象清除掉,

将垃圾对象地址维护到一个空闲列表中,后面有新对象到来时,覆盖掉垃圾对象即可.

特点:

实现简单

效率低,回收后有碎片产生

标记-压缩算法

第一阶段和标记清除算法一样,从根节点开始标记所有被引用对象

第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。

优点

消除了标记-清除算法当中,内存区域分散的缺点,我们需要给新对象分配内存时,JVM 只需要持有一个内存的起始地址即可。消除了复制算法当中,内存减半的高额代价。

缺点

从效率上来说,标记-压缩算法要低于复制算法。

移动对象的同时,如果对象被其他对象引用,则还需要调整引用的地址

移动过程中,需要全程暂停用户应用程序。即:STW

分代搜集

年轻代(Young Gen)

年轻代特点:区域相对老年代较小,对象生命周期短、存活率低,回收频繁。

这种情况复制算法的回收整理,速度是最快的。复制算法的效率只和当前存活对象大小有关,因此很适用于年轻代的回收。而复制算法内存利用率不高的问题,

通过 hotspot 中的两个 survivor 的设计得到缓解。

老年代(Tenured Gen)

老年代特点:区域较大,对象生命周期长、存活率高,回收不及年轻代频繁。

这种情况存在大量存活率高的对象,复制算法明显变得不合适。一般是由标记-

清除或者是标记-清除与标记-压缩的混合实现。

1.Mark 阶段的开销与存活对象的数量成正比。

2.Sweep 阶段的开销与所管理区域的大小成正相关。

3.Compact 阶段的开销与存活对象的数据成正比。

分代的思想被现有的虚拟机广泛使用。几乎所有的垃圾回收器都区分新生代和老

 

以上是关于垃圾回收机制的主要内容,如果未能解决你的问题,请参考以下文章

JVM的垃圾回收机制 总结(垃圾收集回收算法垃圾回收器)

JVM的垃圾回收机制 总结(垃圾收集回收算法垃圾回收器)

Java自用JVM-垃圾回收机制

JVM-11. 垃圾回收概述及算法

JVM详解——垃圾回收算法

JVM垃圾收集机制