GC

GC(Garbage Collection)垃圾收集器

1.GC的对象

在Java堆和方法区中:
一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样;
我们只有在程序处于运行期间的时候才能知道会创建那些对象;
这部分的内存的分配和回收都是动态的,垃圾收集器所关注的就是这部分的内存

而在程序计数器、JVM栈、本地方法栈中每一个栈帧分配多少的内存基本上是在类结构确定下来的时候就已知了。


2. 判断对象是否存活的算法
2. 1:引用算法:

给对象添加一个引用计数器,每当有一个地方引用它的时候,计数器就会加1;当引用失效时,计数器的值就会减1;这样任何时刻计数器为0的对象就是不可能再被使用的。
缺陷:当对象存在着相互引用对方的时候,该算法无法正确判断对象那个是否存活)

2.2:可达性分析算法

通过一系列的“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径就是引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连的时候,则此对象就是不可用的。
在JAVA语言中,可以作为GC Roots的对象包括:
1.虚拟机栈(栈帧中的本地变量表)中引用的对象
2.方法区中 类静态属性 引用的对象
3.方法区 常量 引用的对象
4.本地方栈中的JNI(Native方法)引用的对象。


3.GC算法

1.引用计数法(使用引用算法)
2.标记-清除算法(可达性分析算法)
3.标记-整理算法(可达性分析算法)
4.复制算法(可达性分析算法)
5.分代收集算法(商业虚拟机)

3.1:引用计数法

实现原理:对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就会加1,当引用失效是,引用计数器就会减1.只要对象A的引用计数器的值为0时,则对象A就表示为不被使用,可进行GC回收。
缺陷:1.需要伴随着加减法,影响性能;2.很难处理循环问题

3.1:标记-清楚算法

分为两个阶段(标记和清楚阶段):
标记阶段:首先通过根节点,标记所有从根节点开始的可达对象,而未被标记的对象就是未被标记的垃圾对象
清楚阶段:清除所有的未被标记的垃圾对象。

缺陷:

  1. 效率问题:标记和清除两个过程的效率都不太高;
  2. 空间问题:标记清除后会产生大量的不连续的内存碎片。

GC

3.2:标记-整理算法

标记-整理(标记-压缩)算法在标记-清除算法的基础上做了些优化。和标记-清除算法一样,标记-整理算法也是需要从跟节点对所有可达的对象进行标记。但是之后,不是简单地清除未被标记的对象,而是将未被标记的对象压缩到内存的一端后再进行清理边界外所有的空间。适用于存活对象较多的场合,例如老年代。
GC

3.3:复制算法

与标记-清除算法相比,复制算法是一种相对高效的回收方法,不适用于存活对象较多的场合 ,将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

缺陷:空间浪费
GC

3.4.分代收集算法

把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。
GC