论坛首页 Java企业应用论坛

关于java 垃圾回收的理解

浏览 9771 次
精华帖 (1) :: 良好帖 (1) :: 新手帖 (1) :: 隐藏帖 (5)
作者 正文
   发表时间:2011-05-05   最后修改:2011-05-05
垃圾回收分为两大步骤:识别垃圾 和 回收垃圾
识别垃圾有两大基本方法
1.计数器法
每个对象有一个相应的计数器,统计当前被引用的个数,每次被引用或者失去引用都会更新该计数器。
优点:识别垃圾快,只需判断计数器是否为零。
缺点:增加了维护计数器的成本,无法在对象互相引用的情况下识别垃圾
因此,适用于对实时性要求非常高的系统。
2.追踪法
从根对象(例如局部变量)出发,逐一遍历它的引用。若无法被扫描到,即认定为垃圾
实际情况中一般采用该方法。

回收垃圾最重要的是要最大限度地减少内存碎片。
两种通常的方法:
1.移动活对象覆盖内存碎片,使对象间的内存空白增大。
2.拷贝所有的活对象到另外一块完整的空白内存,然后一次释放原来的内存。

通常第二种方法能够最大的减少内存碎片,但是缺点是在拷贝过程中会终止程序的运行。
引入分级的概念,通常一个程序中大部分对象的生命周期很短,只有小部分的对象有比较长的生命。而恰恰使得拷贝方法性能打折扣的是重复拷贝那些长命的对象。因此,把对象分成几个级别,在低级别呆到一定时间就将其升级。相应地越高级别,回收的次数越少。最理想的情况是,每次回收最低级别的对象全部失效,一次性就可以回收该级别所有内存,提高效率。同时,由于每次只回收一个级别,不需遍历所有对象,控制了整个回收的时间。

由于垃圾识别是通过识别引用来达到,为了增加程序对垃圾回收的控制。提供了引用对象的概念,细化了引用的类型,分别是StrongReference,SoftReference, WeakReference, PhantomReference。其中强引用就是普通的java引用,其他三种类型相当于一个包装器,一方面使得垃圾回收器区分引用类型做不同的处理,另一方面程序通过他们仍然可以得到强引用。
这三种弱类型的类的结构图:


因此一个对象在它的生命周期可能有以下几种状态:strongly reachable,softly reachable,weakly reachable,resurrectable,phantom reachable,unreachable。
引用

    strongly reachable - An object can be reached from the roots without traversing any reference objects. An object begins its lifetime in the strongly reachable state and remains strongly reachable so long as it is reachable via a root node or another strongly reachable object. The garbage collector will not attempt to reclaim the memory occupied by a strongly reachable object.
    softly reachable - An object is not strongly reachable, but can be reached from the roots via one or more (uncleared) soft reference objects. The garbage collector may reclaim the memory occupied by a softly reachable object. If it does so, it clears all soft references to that softly reachable object. When the garbage collector clears a soft reference object that is associated with a reference queue, it enqueues that soft reference object.
    weakly reachable - An object is neither strongly nor softly reachable, but can be reached from the roots via one or more (uncleared) weak reference objects. The garbage collector must reclaim the memory occupied by a weakly reachable object. When it does so, it clears all the weak references to that weakly reachable object. When the garbage collector clears a weak reference object that is associated with a reference queue, it enqueues that weak reference object.
    resurrectable - An object is neither strongly, softly, or weakly reachable, but may still be resurrected back into one of those states by the execution of some finalizer.
    phantom reachable - An object is not strongly, softly, nor weakly reachable, has been determined to not be resurrectable by any finalizer (if it declares a finalize() method itself, then its finalizer will have been run), and is reachable from the roots via one or more (uncleared) phantom reference objects. As soon as an object referenced by a phantom reference object becomes phantom reachable, the garbage collector will enqueue it. The garbage collector will never clear a phantom reference. All phantom references must be explicitly cleared by the program.
    unreachable - An object is neither strongly, softly, weakly, nor phantom reachable, and is not resurrectable. Unreachable objects are ready for reclamation.

对照下面这张图来理解:


这三种弱引用的应用场合:
引用
Weak references enable you to create canonicalizing mappings, such as a hash table whose keys and values will be removed from the map if they become otherwise unreferenced by the program.

典型应用,jdk 的 WeakHashMap, ThreadLocal.

引用
Soft references enable you to create in-memory caches that are sensitive to the overall memory needs of the program. 

Phantom references enable you to establish more flexible pre-mortem cleanup policies than are possible with finalizers.



参考:
1.http://www.artima.com/insidejvm/ed2/gcP.html
2.http://www.iteye.com/topic/401478
   发表时间:2011-05-05  
扯这些有什么鬼用,开发中又用不着。
0 请登录后投票
   发表时间:2011-05-05  
lifeier 写道
扯这些有什么鬼用,开发中又用不着。

呵呵,见谅啊!
0 请登录后投票
   发表时间:2011-05-06  
lifeier 写道
扯这些有什么鬼用,开发中又用不着。

假如实现一些常用图片的缓存功能:

//申请一个图像对象
Image image=new Image();//创建Image对象

//使用 image

//使用完了image,将它设置为soft 引用类型,并且释放强引用;
SoftReference sr=new SoftReference(image);
image=null;

//下次使用时
if (sr!=null) image=sr.get();
else{
//由于GC由于低内存,已释放image,因此需要重新装载;
image=new Image();
sr=new SoftReference(image);
}

这样写,不是better一些。


0 请登录后投票
   发表时间:2011-05-06  
引用

//下次使用时
if (sr!=null) image=sr.get();
else{
//由于GC由于低内存,已释放image,因此需要重新装载;
image=new Image();
sr=new SoftReference(image);
}


if (sr!=null && sr.get()!=null)
else{
image=new Image();
sr=new SoftReference(image);
}

这样才准确把。
0 请登录后投票
   发表时间:2011-05-06  
baitian 写道
引用

//下次使用时
if (sr!=null) image=sr.get();
else{
//由于GC由于低内存,已释放image,因此需要重新装载;
image=new Image();
sr=new SoftReference(image);
}


if (sr!=null && sr.get()!=null)
else{
image=new Image();
sr=new SoftReference(image);
}

这样才准确把。

if判断是干啥用的呢?
0 请登录后投票
   发表时间:2011-05-06   最后修改:2011-05-06
因为你已经将image置为null,有可能因为被垃圾回收而get()不到了,避免空指针。
0 请登录后投票
   发表时间:2011-05-06   最后修改:2011-05-06
niwei 写道
因为你已经将image置为null,有可能因为被垃圾回收而get()不到了,避免空指针。

将image设置为null,就是让GC知道,让SoftReference保存image引用,当GC检测到会抛出OutOfMemoryError时,会清理软引用,此时的image才真正的为空,并需要重新创建对象。
0 请登录后投票
   发表时间:2011-05-06  
Technoboy 写道
niwei 写道
因为你已经将image置为null,有可能因为被垃圾回收而get()不到了,避免空指针。

将image设置为null,就是让GC知道,让SoftReference保存image引用,当GC检测到会抛出OutOfMemoryError时,会清理软引用,此时的image才真正的为空,并需要重新创建对象。


我的意思是你将image设置为null之后再获取时最好将(sr!=null && sr.get()!=null) 这两个判断条件都加上,因为你再次使用时可能sr!=null 但 sr.get()==null。
0 请登录后投票
   发表时间:2011-05-06  
你执行一下下面的代码,将虚拟机参数设置如下:
-Xms15m -Xmx15m -Xmn10m -XX:+UseSerialGC -XX:+PrintGCDetails

public static void main(String[] args) throws Exception
	{
		byte[] b = new byte[1024 * 1024 * 5];
		SoftReference sr = new SoftReference(b);
		b = null;

		byte[] b2 = new byte[1024 * 1024 * 5];

		byte[] b3 = new byte[1024 * 1024 * 5];

		if (sr == null)
		{
			System.out.println("1");
		}
		else if (sr.get() == null)
		{
			System.out.println("2");
		}
		else
		{
			System.out.println("3");
		}
	}


你会发现在执行FullGC之后sr!=null,但sr.get()==null
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics