GC,即java垃圾回收机制。要准确理解GC,我们可以从 “GC的触发”、“回收的对象”以及“做了什么”这三个方面进行法分析。
1.GC的触发
GC分为Minor GC与Full GC。其中,Minor是针对于新生代的回收,Full GC针对于老年代的回收。
java的内存分配是分代分配的,java堆的内存分为新生代与老年代。在新生代中,内存区域又分为一个Eden区域与两个Survivor区域。
GC触发的条件分为:
(1)程序调用System.gc。
(2)系统自身决定。
系统判断是否执行GC:一般情况下,因为对象都是分配在Eden区域中,所以当Eden区域没有足够的空间的时候,将会发起一次Minor GC ;对于Full gc的触发条件是:当老年代没有足够的空间的时候,就会进行一次Full GC。
上面只是一般情况,在实际的运行过程中,还需要考虑一个空间分配担当的问题:
在发生Minor GC 之前,虚拟机会首先检查老年代最大可用的连续空间是否大于新生代的对象总空间,如果这个条件成立,那么Minor GC可以确保是安全的,Minor GC可以进行。如果这个条件不成立,虚拟机则会查看 HandlePromotionFailure 设置值是否允许担当失败。如果允许,那么会继续检查老年代的最大可用空间是否大于历次晋升到老年代对象的平均大小。如果大于,则尝试着进行一次Minor GC,尽管这次GC是有风险的;如果小于,或者HandlePromotionFailure设置值为不允许,则要进行一次Full GC。
2.回收的对象
判断哪些对象需要被回收,主要是依据可达性分析算法。该算法就是通过一系列的称为“GC Roots”的对象作为起点,从这些节点向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何的引用链的时候,则证明还对象是不可达的。
即使在可达性分析中不可达对象也并非是一定要回收的。宣告一个对象的死亡回收需要经过两个步骤。第一步,若在可达性分析过后发现了没有与“GC Roots”有引用链的对象,则将它进行第一次标记并且进行一次筛选,筛选的条件为是否有必要执行finalize()方法。 第二步,若被判定为有必要执行finalize()方法(有必要执行是指该对象覆盖了finalize()方法并且没有被执行过), 则会放入F-Queue队列,并自动创建一个低优先级的finalize线程来执行释放操作。如果在一个对象释放前被其他对象引用,则该对象会被移除F-Queue队列。
3.做了什么
主要做了清理对象,整理内存的工作。当GC线程启动时,会通过可达性分析法把Eden区和From Space区的存活对象复制到To Space区,然后把Eden Space和From Space区的对象释放掉。当GC轮训扫描To Space区一定次数后,把依然存活的对象复制到老年代,然后释放To Space区的对象。