垃圾回收算法
1、相比于C、C++,java jvm能够在内存空间不足时,在系统空闲时进行垃圾回收,而不需要手动出发对象回收;因此在java中只需关心对象的创建,但是由于引用的关系,一些对象无法进行回收,就造成了内存泄漏。
2、如何判断一个对象可以被回收?
引用计数:
一个对象有一个引用就计数加1,当取消一个引用就计数减1,当这个对象没有引用的时候,就是计数为0的时候,就说明这个对象没有引用了,就可以被回收了。
但是引用计数无法解决循环引用的问题,两个对象循环引用,但是两个对象都没有在使用,但是也不能够被当做垃圾进行回收。
可达性算法:
从一个GC ROOT节点出发,如有没有一条线路到达该对象,就说明该对象没有被引用,就可以被回收。
可以作为GC ROOT 的对象:
( 1).虚拟机栈(栈帧中的本地变量表)中引用的对象。
(2).方法区中类静态属性引用的对象。
(3).方法区中常量引用的对象。
(4).本地方法栈中JNI(即一般说的Native方法)引用的对象。
3、jvm堆模型
新生代:Edon、S1、S2 新生代中的对象大都是生命周期较短的对象。
老年代:经过多次GC都没有被回收的对象。
4、垃圾回收算法
标记清除算法:主要是针对新生代的对象,标记可以被回收的对象,然后将标记的对象进行清除,这种算法会造成出现很多空间碎片,当有大的对象出现的时候,因为没有连续的空间,因此还得进行一次垃圾回收。
复制算法:将空间一分为二,每次只使用其中的一块空间,当空间用没了,就将还存活的对象复制到另一个空间中,然后将之前的空间一次性清除。解决了空间碎片的问题,但是将可使用的内存空间减小为原来的一半,代价有点大。
标记整理算法:标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。
分代回收算法:把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记—清理”或者“标记—整理”算法来进行回收。