JVM垃圾回收
一、GC原理
GC(Garbage Collection:即垃圾回收器)
将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停。
1、 对新生代的对象的收集称为minor GC
2、对旧生代的对象的收集称为Full GC
3、程序中主动调用System.gc()强制执行的GC为Full GC
JVM对象的引用分为了四种类型:
1 、 强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)
2、 软引用:软引用是java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)
3、 弱引用:在GC时一定会被GC回收
4、 虚引用:由于虚引用只是用来得知对象是否被GC
二、对象被标记为垃圾的方法
java堆区和方法区则不一样,线程共享的区域,这部分内存的分配和回收是动态的,正是垃圾收集器所需关注的部分
引用计数的方式:
引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为1.当任何其它变量被赋值为这个对象的引用时,计数加1(a=b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器-1.任何引用计数器为0的对象实例可以被当做垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器-1。
计数方式的缺陷:无法解决循环依赖的问题
public class GcDome{
public static void main(String[] args){
//分为六个步骤
GcObject obj1=new GcObject();//Step 1
GcObject obj2=new GcObject();//Step 2
obj1.instance=obj2;//Step 3
obj2.instance=obj1;//Step 4
obj1=null;//Step 5
obj2=null;//Step 6
}
}
class GcObject{
public Object instance=null;
}
obj1: 1(Step1)——2(Step 4)——1(Step 5)
obj2: 1(Step 2)——2(Step 3)——1(Step 6)
- Step 1:GcObject实例1的引用计数加1,实例1的引用计数=1;
- Step 2:GcObject实例二的引用计数加1,实例二的引用计数=1;
- Step 3:GcObject实例二的引用计数再加1,实例二的引用计数=2;
- Step 4:GcObject实例1的引用计数再加1,实例一的引用计数=2;
- Step 5:栈帧中的obj1不再指向java堆,GcObject实例1的引用计数减一,结果为1;
- Step 6:栈帧中odj2不再指向java堆,GcObject实例二的引用计数减一,结果为1;
在Step 5,和Step6时对象置为null,想要回收对象,可是此时如果采用的引用计数算法的话,他们的计数为1,导致没有办法回收,两个实例所占的内存将得不到释放,这便产生了内存泄漏。
可达性分析
从一个节点CG Roots开始,寻找对应的引用节点。当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点,无用的节点将会被判定为是可回收的对象。
在java语言中,可作为GC Roots的对象包括下面几种:
1)虚拟机栈中引用的对象(栈帧中的本地变量表);
2)方法区中类静态属性引用的对象;
3)方法区中常量引用的对象;
4)本地方法栈中JNI(Native方法)引用的对象