- 由于栈中的线程都是每个线程跑完后,直接被清除掉,所以垃圾清除时,无需考虑该栈中情况(栈中的生命周期是跟随线程)
- 堆中的对象一直被创建,如果一直被创建未进行清除时,可能会导致堆中内存爆满溢出的情况;所以针对该情况,我们需要对堆中的内容进行垃圾回收
一、垃圾回收方法:
1、新生代-复制算法
该算法的核心是将可用内存按容量划分为大小相等的两块, 每次只用其中一块, 当这一块的内存用完, 就将还存活的对象复制到另外一块上面, 然后把已使用过的内存空间一次清理掉;
优缺点:
优点:内存数据不需要整理
缺点:内存使用率只有一半
2、老年代-标记清除算法
该算法分为“标记”和“清除”两个阶段: 首先标记出所有需要回收的对象(可达性分析), 在标记完成后统一清理掉所有被标记的对象.
优缺点:
优点:内存使用率100%
缺点:内存被弄的支离破碎,无连续性:
记清除后会产生大量不连续的内存碎片, 空间碎片太多可能会导致在运行过程中需要分配较大对象时无法找到足够的连续内存而不得不提前触发另一次垃圾收集.
3、老年代-标记整理算法
标记清除算法会产生内存碎片问题, 而复制算法需要有额外的内存担保空间, 于是针对老年代的特点, 又有了标记整理算法.
标记整理算法的标记过程与标记清除算法相同, 但后续步骤不再对可回收对象直接清理, 而是让所有存活的对象都向一端移动,然后清理掉端边界以外的内存.
优缺点:
优点:内存利用率100%
缺点:费时,因为都需要将过期的垃圾全部都移动到一端后,才可以直接消除;
二、垃圾回收算法:
如何判断对象的存活:
2.1 引用计数法
给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的。
这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。 所谓对象之间的相互引用问题,如下面代码所示:除了对象objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为0,于是引用计数算法无法通知 GC 回收器回收他们
- 优点:快,方便,实现简单。
- 缺陷:对象相互引用时(A.instance=B 同时 B.instance=A),很难判断对象是否该回收
2.2 可达性分析算法
这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
GC Roots的话我们可以看成是一个对象,如果其中有引用对象的话,都认为这个对象是还在使用中,不可以被回收
作为 GC Roots 的对象包括下面几种:
- 当前虚拟机栈中局部变量表中的引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象