简单介绍垃圾回收算法
最近在看深入了解java虚拟机这本书,java最让人心动但是最复杂的就是它的自动内存管理机制,而对于系统来说,只有采用合适的内存管理,才能使得我们的系统响应更快。
简单介绍垃圾回收算法:
1.标记-清除算法:
概念:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象
那么就有疑问了,怎么标记的呢?
标记过程:
(1)引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数值就加1;当引用失效时,计数器就减1;任何时刻计数器为0的对象就是不可能再被使用的
这个咋一看觉得很美好,但是遇到一种场景下,对象objA和对象objB都有字段,并且令objA和objB互为对方的某个字段,此时置两个对象都为null,显然可以知道这两个对象是不能 再被访问,但是依照引用计数法来看的话显然不能被回收,因为都加了1,但是我们再也用不了了,引用计数法达不到我们的目的,所有java虚拟机并没有使用引用计数器来处理
(2)可达性分析算法:当一个对象到GC Roots没有任何引用链相连,则证明此对象不可达到
什么是GC Roots?
在java语言,可作为GC Root的对象:
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中类静态属性引用的对象
方法区中常量的引用的对象
本地方法栈中JNI引用的对象
对于java虚拟机采用的就是GC Roots,那到底是怎么判断对象是生存还是死亡呢?
一个对象要真正地宣布死亡,需要经历至少两次的标记过程,并进行筛选,筛选条件是此对象是否有无必要执行finalize()方法。当对象没有覆盖finalize方法或者finalize方法已经被 虚拟机调用过,则视为没有必要执行
如果这个对象被判定为有必要执行finalize()方法,则这个对象会放置在一个F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程执行它。而对 于对象来说,finalize()方法是对象逃脱死亡的最后机会
演示对象自我拯救的过程:
public class FinalizeEscapeGC {
public static FinalizeEscapeGC SAVE_HOOK=null;
public void isAlive(){
System.out.println("yes,i am still alive");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize method executed");
FinalizeEscapeGC.SAVE_HOOK=this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOOK=new FinalizeEscapeGC();
SAVE_HOOK=null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK!=null){
SAVE_HOOK.isAlive();
}else {
System.out.println("no,i am dead");
}
SAVE_HOOK=null;
System.gc();
Thread.sleep(500);
if (SAVE_HOOK!=null){
SAVE_HOOK.isAlive();
}else {
System.out.println("no,i am dead");
}
}
}
2.复制算法
概念:将可用的内存容量划分为大小相等的两块,每次只使用其中的一块,每次垃圾回收对整个半区进行内存回收
==>演变
将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中的一块Survivor。回收时,将Eden和Survivor中存活的对象一次性复制到另一块Survivor空 间。HotSpot默认Eden:Survivor=8:1,这意味着10%内存被浪费。但当Survivor不够用时,需要依赖老年代进行分配担保
3.标记整理算法
概念:让所有存活对象都向一端移动
目的:节省jvm内存的使用

浙公网安备 33010602011771号