在Java中支持GC的概念,GC有两种调用形式:自动调用、手工调用:
(Runtime.getRuntime().gc())
在写代码的时候,很少手工调用,因为不是实时的。那为什么不是实时的?因为GC不是把没用的空间腾出来就完毕了。比如说,有十处垃圾点,直观感受回收就是把垃圾挪出去就行,其实不是。因为一旦要进行GC,至少应该先找到垃圾,而后再把垃圾的空间填新东西。
自动调用
JVM什么时候会自动调用呢?回答这个问题,就牵扯到了两类的GC操作环境。先看下图
Eden:伊甸园 Survivor:存活区 Tenured:老年区
- 当程序之中需要产生新的实例化对象(关键字new、对象克隆、反射实例化)的时候,因为一定要进行内存空间的开辟,所以此时需要申请新的内存空间
- 新对象要申请的对象的空间默认都在伊甸园区(新生)进行开辟,因此需要判断伊甸园区是否有空余的内存空间。
- 如果有空余的内存空间,则直接在伊甸园区开辟新的堆内存空间,此时不会发生有GC处理;
- 如果新对象无法在伊甸园空间申请出新的空间,那么就表示现在的伊甸园的空间不足,不足就需要将那些无用的新对象进行回收(此时叫Minor GC)
- 当回收完毕后还要判断该空间是否有空余的空间可以容纳新的对象,如果可以容纳,则开辟新空间,保存新对象
- 如果此时伊甸园区即时执行了Minor GC后发现依然没有可以被回收的对象,那么这时候就会判断存活区是否有空间(存活区一般与伊甸园的比率是 1:1:8)
- 如果存活区有空余空间,则将那些活跃的伊甸园区的部分对象直接保存给存活区,这样就相当于伊甸园区可以腾出部分的空间(这个空间非常的小)来,供新对象进行使用
- 如果此时存活区依然满了(空间不足),则继续向老年代进行内存空间的申请。向老年代进行空间的申请,首先会判断老年代的空间是否空余
- 如果空余则将存活区中的活跃对象保存在老年代,而后存活区得到了空间释放,伊甸园区得到了空间释放,则对象空间申请成功
- 如果老年代也是满的,那么这个时候会执行FULL GC(又叫完全GC、major GC)进行老年代的内存释放
- 如果释放成功,则进行对象的保存,如果释放不成功则表示已经没有无用的内存空间了,那么就会抛出OOM(OutOfMemoryError)
这就是对象的创建以及垃圾回收流程,也是GC自动操作的触发条件
关于上面流程还有一个面试题:自动的GC什么时候触发?
GC的触发有两类:
- Minor GC:发生在年轻代内存空间,当年轻代内存空间不足时会进行触发,释放年轻代中不活跃的对象
- Full GC(Major GC):发生在老年代的内存空间,当老年代的内存空间不足时会自动触发Full GC,如果触发Full GC之后,内存空间依然不足,则会产生OutOfMemoryError的错误信息