java jvm 垃圾收集算法

6 篇文章 0 订阅
4 篇文章 1 订阅

引用计数算法

由于之前在看《深入理解java虚拟机》之前先看了《深入理解android内核设计思想》,两本书上都有写到这个算法。关于如何实现java的垃圾收集机制,就是在object类上加上一个引用计数器,我们知道java中所有类都继承自object,当这个对象被人引用一次那么引用计数器就加1,引用结束了就减1,垃圾收集的时候就简单了,当这个对象没有人用了,也就是计数器为0了,那么就把它回收掉。但是主流的jvm里面并没有选用这个算法。因为它很难解决对象 之间循环引用 的问题。不过在安卓虚拟机里面有一个智能指针的概念倒是跟这个差不多,通过一个巧妙的办法解决了相互循环引用 的问题。
先看一个这个问题到底是怎么产生的。
比如说
<pre name="code" class="java">package test;

public class Demo {
	private Object count = 0;

	public static void main(String[] Args) {
		new Demo().test();
	}

	private void test() {
		Demo d1 = new Demo();
		Demo d2 = new Demo();
		d1.count = d2;
		d2.count = d1;
		d1 = null;
		d2 = null;
		System.gc();
	}
}

 上述就是一个典型的相互引用的例子,先说一个在安卓上的智能指针是如何解决的,它通过引入弱引用解决了这个问题,规定强引用计数为0时,不论弱引用是否为0都可以delete自己,在安卓中这个规则是可以调整的,这样虽然成功的解决了“死锁问题”,但是会有产生野指针的可能 ,比如d1强指针数为0了该 回收了,可是d2还持有它的弱引用,这里用这个指针来访问d1会产生严重的问题。安卓上因此有一个特别规定,弱指针先升级为强指针 ,才能访问它所指向的目标对象 。可能会有人问,java不是没有指针么。。java是没有。是因为jvm已经把指针的问题解决了,我们这里讲的是jvm和android系统。 
jvm没有采用引用计数算法那么它采用的是什么呢。是下面的这个算法。

可达性分析算法

这个算法的基本思想是通过 叫做GC Roots的对象作为起始点,从这些节点 向下搜索,搜索走过的路径叫做引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可引用的。在java C#包括古老的Lisp语言中都是用这个方法判断对象是否存活的。

java中可做为GC Roots的对象 :

虚拟机栈中引用的对象

方法 区中类静态发生引用的对象 

方法区中常量 引用 的对象 

本地方法栈中JNI引用的对象 

java中的各种引用

由强到弱依次分为:

强引用

软引用

弱引用

虚引用

曾经还用到过,因为开发一个安卓app,里面有一个功能是播放 gif图,图的解码器是用的一个开源的项目 ,但这个项目存在 一个问题就是经常会oom(outofmemory),自己还改良一下,就是通过引用软引用和弱引用,希望能加大垃圾收集器的回收力度。结果效果并不好。。那么接着说这四个引用的强度区别 

强引用就是我们通常用的new

软引用就是在要发生oom之前进行回收

弱引用就算内存够用也会被回收

虚引用唯一的作用就是在回收的时候收到一个系统 通知 。

这里我写了一个测试类

package test;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;

public class Demo {

	private String name;

	public Demo(String name) {
		super();
		this.name = name;
	}

	public Demo() {
		super();
	}

	public static void main(String[] Args) {
		new Demo().test();
		System.gc();
	}

	@Override
	protected void finalize() throws Throwable {
		// TODO Auto-generated method stub
		super.finalize();
		System.out.println("我死啦我死啦" + this.name);
	}

	void test() {
		Demo a = new Demo("soft");
		SoftReference<Demo> d1 = new SoftReference<Demo>(a);
		Demo b = new Demo("weak");
		WeakReference<Demo> d2 = new WeakReference<Demo>(b);
		Demo c = new Demo("pham");
		ReferenceQueue<Demo> temp = new ReferenceQueue<Demo>();
		PhantomReference<Demo> d3 = new PhantomReference<Demo>(c, temp);
	}
}
运行结果几次各有不同:

结果 1:

我死啦我死啦pham
我死啦我死啦weak
我死啦我死啦soft
我死啦我死啦null

结果2:

我死啦我死啦pham

结果3:

我死啦我死啦pham
我死啦我死啦weak

这里可以看出虚引用的确是一点活路都没有,而且垃圾回收也的确是不确定 的。不过总的强度没有错误 ,是从弱到强进行回收的


垃圾收集算法

标记-清除算法

算法如其名,就是先标记出哪个是需要回收的,然后再进行回收,不过有一个严重的问题,现在我们想象内存是一个棋盘,然后被标记的是几个块,现在就是可用的内存和要回收和内存块是相间的,跟熊猫是的。回收过后就会产生好多好内存碎片,以至于以后要分配较大的内存的时候 找不到地方。

复制算法

它将可用内存分成的两大块,每次只使用其中一块,当这一块用完了,就将存活的对象复制到另一块上去,然后那块就完全被 清理干净 ,典型的用空间换时间的算法,这虽然效率高,但是未免也太费内存了。

标记-整理算法

跟标记清除算法差不多,只不过为了解决它的碎片问题又加 上了一个碎片整理功能 。

分代收集算法

这是当前虚拟机在采用的算法,就是根据各个年代(新生代和老年代)采用不同的算法进行回收,新生代每次都 有大量对象死去,那么就采用复制算法,只需要付出少量对象的复制 成本 ,而老年代中存活率高,所以采用整理或清除算法。

我发现其实好的算法并不是单一职能,都 是几个算法结合起来使用,这是一个例子,又比如linux中的文件系统存储分配算法,也是采用链表索引加内存块分配 算法结合的办法。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值