虚拟机栈,程序计数器,本地方法栈随线程的生和死而决定,垃圾收集一般不考虑这个区域。引用计数算法当其他对象引用它时,计数器就加1,引用失效就减去1.但是存在一个缺陷,就是互相引用后让两个对象不再被访问时,导致计数器不为0.
可达性算法分析,可以作为GC Roots的对象包括:虚拟机栈(栈帧中的本地变量表)中引用的对象。方法区中类静态属性引用的对象。方法区中常量的引用对象。本地方法栈中JNI引用的对象。
强引用指的是“Object() a = new Object()”只要强引用还存在,垃圾收集器就不会回收掉这类引用。
一个对象是否必死需要经过两次标记过程,第一次判断是否为GC Roots可达,没有引用链的话会被标记一次并进行筛选,筛选条件是判断次对象有没有必要执行finalize()方法,如果没有覆盖finalize()方法,或者虚拟机已经调用过finalize()方法,则判定为没有必要执行。如果判断为有必要执行,就被被放置在一个F-Queue队列之中。虚拟机会自动建立一个低优先级的Finalize线程去执行finalize()方法。任何一个对象的finalize()方法都只会被系统调用一次。
判断方法区中是否为一个无用的类需要满足3个条件:
1.该类的所有实例已经被回收,也就是java堆中不存在该类的任何实例。
2.加载该类的ClassLoader已经被回收。
3.该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
在大量使用反射,动态代理,GCLib等ByteCode框架,动态生成JSP以及OSGi这类频繁自定义ClassLoader的场景都需要虚拟机具备卸载的功能,保证永久带不会溢出。
标记清楚算法的标记和清楚过程效率较低,还有一个问题是在清楚后会产生大量不连续的内存碎片。空间碎片太多会导致在需要分配一块较大的内存时无法找到足够的连续碎片,需要提前触发一次垃圾收集动作。
复制算法,将内存划分为两个大小相等的区域,将存活对象在另一块区域移动堆顶指针,按顺序复制分配过去,然后一次清理原来那块的内存。新生代中98%的对象存活时间很低。不需要按1:1进行内存区域的划分
parallel Scavenge和Parallel old通过提高吞吐量来提高效率。
CMS和G1通过减少停顿时间,CMS过程初始标记,并发标记,重新标记,并发清楚。G1初始标记,并发标记,最终标记,筛选回收。