垃圾回收
概述
java是支持自动垃圾回收的,有些语言不支持,需要手动
自动垃圾回收不是java语言首创的
垃圾回收关系的问题:
哪些区域需要回收:堆、方法区
什么时候回收:对象变为垃圾时
如何回收:
java的自动垃圾回收经过长时间的发展,已经非常强大。
什么是垃圾?
垃圾是指在运行程序中没有任何引用指向的对象;
为什么需要GC(垃圾回收)?
1.如果不及时对内存中的垃圾对象进行清理,那么,这些垃圾对象所占的内存空间会一直保留到应用程序结束,被保留的空间无法被其他对象使用。甚至可能导致内存溢出。
2.除了释放没用的对象,垃圾回收也可以清除内存里的记录碎片,将内存碎片进行整理(以便于创建数组,因为它需要连续的内存空间)
内存溢出和内存泄漏
内存溢出:经过垃圾回收后,内存中仍然无法存储新创建的对象,内存不够用溢出。
OutofMemory(OOM)内存溢出
内存泄漏:例如IO流 close jdbc连接 close等close资源没有关闭时,这些对象我们已经不再用了,但是垃圾回收器又不能将其判定为垃圾,这些对象就默默的占用着内存,称为内存泄漏;如果大量的此类对象存在,也是导致内存溢出的原因。
其实更应该叫内存遗漏
自动内存管理
好处:解放程序员,对内存管理更合理,自动化
不好的:对程序员管理内存的能力降低了,解决问题的能力变弱了,不能调整垃圾回收的机制。
垃圾回收相关算法
垃圾回收一般分为两个阶段,垃圾标记阶段和垃圾清除阶段
垃圾标记阶段算法
此算法的目的是:判断对象是否是垃圾对象,是否有引用指向对象
判断对象是否为垃圾对象一般有两种标记算法:引用计数算法(现在的jvm中并没有被使用)和可达性分析算法(java使用的)
1.引用计数算法:
有个计数器来记录对象的引用数量
缺点:需要维护计数器,占用空间,频繁操作需要时间开销
无法解决循环引用问题,即多个对象之间相互引用,没有其他外部引用指向它们,计数器都不为0,就不能回收,产生内存泄漏。
2.可达性分析算法(根搜索算法):
实现思路:从一些为根对象(GCRoots)的对象出发去查找搜索,与根对象直接或间接连接的对象就是存活对象,不与根对象引用链连接的对象就是垃圾对象,
GCRoots可以是哪些对象?
1.在虚拟机栈中的方法中被引用的对象
2.方法区中存储的静态属性引用指向的对象
3.作为同步锁使用的 synchronized
4.在虚拟机内部使用的对象
对象的finalization机制
已经标记为垃圾了,在对象真正被销毁回收之前,会调用一次Object类中的回调方法:finalize();
(满足复活机会后,这个对象可以复活,但是只能复活一次,下次被回收时,不会调用finalize方法,即机会只有一次)
自己不要在程序中调用finalize方法,它是留给垃圾回收器调用的
有了finalization机制的存在,在虚拟机中把对象状态分为3种:
1.可触及的:正常的对象,不是垃圾,与根对象连接的
2.可复活的: 判定为垃圾了,但是还没有调用finalize方法,在finalize法中对象可能会复活
3.不可触及的:再次判定为垃圾了,即finalize方法也被执行过了
垃圾回收阶段算法
当成功分出内存中存活对象和死亡对象后,GC接下来的任务就是执行垃圾回收,释放掉无用对象所占用的空间;
1.标记--复制算法:
将内存分为大小相同的两份空间,把当前使用的空间中存活的对象,复制到另一个空间中,将正在使用的空间中垃圾对象清除
优点:减少内存碎片
缺点:如果需要复制的对象数量多,则效率会低
适用场景:存活的对象少 ,垃圾对象多时,如新生代适合使用标记复制算法
2.标记--清除算法
清除不是真正的把垃圾对象清除掉
将垃圾对象地址维护到一个空闲列表中,后面有新对象到来是,覆盖掉垃圾对象即可。
特点:实现结构相对简单,效率低,回收后有碎片产生
3.标记--压缩算法
也叫标记--整理算法
产生背景:复制算法的高效性是建立在存活对象少,垃圾对象多的前提,是十分适用于堆中的新生代的,但是老年区中大部分都是存活对象,如果一味地使用复制算法,由于存活对象很多,复制的成本也会很高。标记--清除算法可以应用在老年区,但是因为效率较低,还会产生内存碎片等缺点,我们就产生了标记--压缩算法。
第一阶段就是标记清除算法,从根节点开始标记所有被引用对象
第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间
这个算法比标记--清除算法相比较,就是多出了一步内存碎片整理;所以这个算法又被称为标记-清除-压缩(Mark-Sweep-Compact)算法。
垃圾回收算法小结
从效率上来说,标记--复制算法可以说得上是最优的,但是他因为需要将内存分为两半,所以浪费了太多内存。为了兼顾速率,空间开销,是否移动对象这三个指标,标记--压缩算法算的上是中规中矩,单缺点就是效率太慢,因为它相比较标记--清除算法,多了一步内存碎片的整理,这也使得它不会产生内存碎片。
![](https://img-blog.csdnimg.cn/img_convert/42f1d6f134ca7fa3c554fd98c676e267.png)