JVM垃圾收集【一】

什么是垃圾?怎样确定垃圾?


    背景:垃圾收集并非java语言的伴生产物,垃圾回收比java更加久远,1960年MIT的Lisp是第一门真正使用内存冬天分配和垃圾收集的语言。经过50多年的发展,内存动态分配和回收技术发展到了相当成熟的阶段,除了java语言,很多其它计算机语言也使用动态内存分配与垃圾回收,例如ruby、python等。

    什么是内存垃圾,即那些不会被后续程序使用到的内存对象和结构。

    怎么确定内存垃圾,常用的有两种算法:引用计数算法和根搜索算法。

    引用计数算法,如名称描述,即对内存中的每一个对象都设置一个计数器。为对象第一次分配内存时,计数器为1,当有其它地方引用该对象时,该对象的计数器加1,引用失效时,计算器减1,直到计算器为0时,该对象则可以被回收。该算法简单而且非常有效,在很多语言中均使用了该算法进行垃圾回收,例如python语言。但是该算法无法解决相互引用的问题,例如代码1所示, 当这类语言遇到相互引用时,则会导致内存泄露,所以程序员在使用该类语言时需要注意相互引用的问题。

    根搜索算法,该算法的思想是从一系列根对象出发,遍历对象引用链,从所有根对象都无法到达的对象,则是能被回收的对象。在主流的商用计算机语言(java c#等)均使用根搜索算法作为垃圾回收的算法。在java语言中,作为垃圾回收时的根的对象有以下几类:虚拟机栈中引用的对象;方法区中类静态属性引用的对象;方法区中常量引用的对象;本地方法栈中JNI的引用对象。JVM进行GC时,从以上几类根对象出发,遍历内存中的对象,没有被引用的对象,则是可能(GC调用有jvm触发)被回收的对象。在JDK1.2之前,引用被定义得很具体,一个对象要么被引用,要么不被引用。在JDK1.2后,java对引用进行了概念扩充,引用被分为强引用(strong reference),软引用(soft reference),弱引用(weak reference),虚引用(phantom reference),这四种引用强度依次减弱。

    在根搜索算法中不可达的对象中,这些对象也不是立即被当作垃圾进行回收,而是有一个“缓刑期”。即对象要真正被回收,至少要进行两次标记过程。第一次标记将所有不可达的对象进行标记,并且进行筛选,筛选出那些finalize方法被覆盖的对象并且该对象没有被调用finalize(),则将该对象放置到一个F-Queue队列中,其余对象则被回收。第二次标记即对F-Queue队列中的对象进行调用finalize()方法,如果在finalize方法中,对象实现了自我救赎(例如把this指针赋值给其它对象),那么将移除“即将回收”对象集合,否则下次对“即将回收”对象集合进行真正垃圾回收。

    代码1中所示逻辑,在引用计数算法则对象不能被回收,然而在java中会被回收,可以利用相应参数查看结果。


代码1

package jvm.com.cn;

//-verbose:gc -XX:+PrintGCDetails -XX:SurvivorRatio=8
public class ReferenceCountingGC {
	
	public Object instance = null;
	
	private byte[] bigSize = new byte[2*1024*1024];

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		ReferenceCountingGC instanceA = new ReferenceCountingGC();
		ReferenceCountingGC instanceB = new ReferenceCountingGC();
		
		instanceA.instance = instanceB;
		instanceB.instance = instanceA;
		
		instanceA = null;
		instanceB = null;
		
		System.gc();
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值