真正宣告一个对象死亡,至少要经历两次标记过程。对象没有与roots相连,将会被第一次标记,而且会被进行筛选,栓选的条件是是否有必要执行finalize()方法。如果判断有必要执行该方法,就会放到F-Queue中,在Queue中再进行第二次标记,就会被GC回收,中间过程有一个没有执行,都不会被回收。
1:先谈谈引用
java中引用包括四种类型,分别是强引用、弱引用、软引用、虚引用。
优先级:强引用>弱引用>软引用>虚引用
强引用是代码中普遍存在的引用,只要强引用还存在,GC用于不会回收被引用的对象;
软引用就是一些还是有用但并非必须的对象,如果系统内存不够,快要溢出了,就会将这个对象进行回收,如果回收还是没有足够的内存,还是会抛出内存溢出异常;
弱引用是制的是非必须对象,比软引用更弱,下此次GC的时候是肯定会被回收的。
虚引用唯一目的就是将这个对象回收的时候得到一个系统通知。
其实搞这么多引用出来,就是区分引用对象的优先级,当内存不够的时候,GC回收哪些对象,显然优先级别比较低的对象优先被回收。一切发明的目的就是回收对象,增大空闲内存。
2:对象是否存活的算法
①:引用计数算法
有点古老,就是根据引用计数器来计算引用对象对象被引用的次数,如果次数为0,则说明没有对象引用,就会被GC回收,实际这种情况有很大弊端,如果遇到对象之间相互循环引用,显然对象计算器一直部位0,但是一直没被回收。详情见《深入理解JAVA虚拟机》page 62-63.
②:可达性分析算法
通过设置一个GC Roots,就像二叉树里面的Root(根节点),就是从GC Roots到这个对象不可达到,也就是该对象没有Roots,就会被GC回收。
GC对象可以是下面几种
虚拟机栈(栈帧中的本地变量表)中的引用对象。
方法区中静态属性引用的对象
方法区中常量引用的对象
本地方法中引用的对象
3:垃圾回收算法
①:Mark-Sweep
先标记,然后统一回收。
缺点:效率低下,标记、清除效率都不高;标记清除会产生很多不连续碎片,假如此时需要分配大的对象时,不能找到足够大的内存保存该对象。
②Coping
简单理解就是将内存分为两个区域,每次只用其中一个区域,另一个区域作为保存,当前面一个区域用完了,就将还存活的对象复制到另一个区域,然后将前面那个区域clear掉。
缺点:如果对象存活较多,coping的也会较多,效率会很低。
③:Mark-Compact
类似与①,区别就是将要回收的对象移到一段,这样就不会产生很多零碎的空间碎片,然后所有进行回收。
④:Generational Collection
将放在堆中的对象分为老年代和新生代。
老年代就是对象存活率很高的对象,运用①或者③进行回收
新生代就是存活率很低,运用②进行回收。