1. 判断对象已死
1.1 引用计数法:对象中设置一个计数器,每当有一个对方引用该对象时,该计数器加1,每当有一个引用失效时,该计数器减1.
缺点:不能对象间解决循环y引用的问题。大多数主流的虚拟机都没有用引用计数法来判断对象是否已死
1.2 可达性分析法:通过一系列“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程走过的路径称为“引用链”,如果某个对象到GC Roots之间没有任何引用链相连,或者说从Gc root到这个对象不可达时,则判断该对象已死,可以被回收。垃圾回收器会收集那些不是gc roots且没有被gc roots引用的对象。
可做GC Root的对象:虚拟机栈中引用的对象;如下的s
public static void testGC() {
StackLocalParameter s = new StackLocalParameter("localParameter");
s = null;
}
方法区中类静态属性引用的对象,如下的m,当然,下面例子中s也是gc root
public class MethodAreaStaicProperties {
public static MethodAreaStaicProperties m;
public MethodAreaStaicProperties(String name) {}
public static void testGC(){
MethodAreaStaicProperties s = new MethodAreaStaicProperties("properties");
s.m = new MethodAreaStaicProperties("parameter");
s = null;
}
}
方法区中常量引用的对象:如下的m,同上,下面例子中s也是gc root
public class MethodAreaStaicProperties {
public static final MethodAreaStaicProperties m = MethodAreaStaicProperties("final");
public MethodAreaStaicProperties(String name) {}
public static void testGC() {
MethodAreaStaicProperties s = new MethodAreaStaicProperties("staticProperties");
s = null;
}
}
本地方法栈中引用的对象
引用:强引用:指在程序代码中普遍存在的引用赋值。
软引用:一种还有用,但非必须的对象。如只被软引用关联着的对象,在系统将要发生内存溢出异常之前,会把这些软引用的对象列进回收范围进行二次回收, 若 这次回收后还没有足够的内存,则才会抛出内存溢出;
弱引用:也是有用非必须的对象,比软引用更弱。被弱引用关联着的对象,只能存活到下一次垃圾回收发生之前,垃圾回收器开始工作时,无论内存是否足够, 都会回收掉只被弱引用关联的对象;
虚引用:最弱的引用关系,无法通过一个虚引用获得一个对象实例,为一个对象设置虚引用关联的唯一目的是为了在这个对象被回收
时受到一个系统通知。
2.垃圾回收算法
2.1 标记清除
缺点:1执行效率不稳定,可能会存在大量需要被标记的对象;2产生过多内存碎片,以使需要分配大对象时无法找到连续的内 存空间而触发另一次垃圾回收
2.2 标记复制(用于新生代的垃圾收集算法)
将内存按容量划分为大小相同的2块,每次只使用一块,当这一块的内存用完了,就将还存活的对象复制到另外一块上,然后把已使用的内存空间一次清理掉 。
缺点:可使用内存变成了原来的一半,空间浪费较多
大多数商用java虚拟机都采用这种标记复制法。由于大量的对象都是朝生夕死,所以并不需要按照1:1来划分新生代内存。
HotSpot虚拟机采用的策略是:将新生代分为一块较大的Eden区和2个较小的Survior区(Eden和Survior默认大小为8:1),每次分配内存只用Eden和其中一块survior区,垃圾收集时,将存活的对象移到另一个survior区,然后直接清理调Eden和已使用的那个survior区.
2.3 标记整理(用于老年代的垃圾收集算法)
标记后,将还存活的对象都向内存一端的空间移动,然后清理掉边界以外的内存。
分代收集法
新生代的对象大多朝生夕死,存活的对象很少,因为使用标记复制算法;老年代使用标记整理。
虚拟机内存根据对象的存活时间分为了新生代young,和老年代Old区,其中新生代区又分为了Eden区和两个survior区(8:1),两个survior区又叫From区和To区
新生代垃圾回收:
大多数情况下,对象会分配在Eden区,当Eden区空间不够时,会触发一次Minor Gc,经过Minor Gc后,Eden区的大部分对象会被回收,而存活下来的对象,会被送到From区,若from空间不够,直接送到old区。对象刚在eden区分配,默认age是1,之后对象在survior区中每经历一次minor gc,则age增加1,只有age到达16,才会被送到old区。这是默认的,具体到底age到达多少才被送往old区,有虚拟机参数可以调节。
动态对象年龄判定:
如果survior空间中相同年龄的对象总和大小 大于survior空间的一半,则会将年龄大于等于该年龄的对象 移动到old区。