注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭州 QA Team

务实 专注 分享 做有态度的QA

 
 
 
 
 

日志

 
 

Java引用类型与Garbage Collection的关系  

来自史彦诚   2014-03-19 15:40:38|  分类: 性能测试 |举报 |字号 订阅

  下载LOFTER 我的照片书  |

我们都知道在Java中,如果一个对象没有持有引用,那么在程序代码中就无法使用这个对象。而这样的对象将随后被垃圾回收线程销毁。

然而,你不知道的是,某些对象即便拥有引用,也仍然会被回收掉。因为在Java中,引用的类型并不止一种。

对象的可及性

在Java里,我们通过引用来保存对对象的地址,进而完成对对象的使用。如果一个对象具有一个或多个引用,我们就称这个对象是可达的(可被引用到,可被使用到)。

当我们声明并实例化一个对象,如 OneClass myClass = new OneClass();

上述语句将在JVM堆区中开辟一块空间用于放置新创建的OneClass的实例(即对象),而在JVM栈区中存储myClass(称为引用)。myClass存储的是OneClass实例的地址。

此时,OneClass的实例是可达的,因为有myClass这个引用指向它。 随后我们会看到,myClass是一个强引用。因为有myClass这个强引用存在,垃圾回收器(GC)发生时不会回收掉myClass所指向的这个OneClass的实例。

为什么有多种引用类型

Java中的引用类型有四种,分别是强、软、弱、虚引用。稍后会介绍这四种引用的区别。在这里,先引援一个形象的例子,来说明为何会有这四种引用类型。

假象一下,现在我们的电脑上安装了一个Java语言实现的员工信息查询系统。通过这个员工信息查询系统,我们可以查看到员工的信息。而员工的信息是存储在磁盘文件或者数据库中。

作为用户,我们常常想要回头查看几分钟之前看过的员工信息。

对于这个use case,从实现上来说,很容易想到两种编码方式: 
1.将所有查看过的员工信息都保存在内存中,方便以后翻回来查看。 
2.不保存查看过的员工信息,需要查看时,重新构建一个新的员工信息的数据结构。

很显然,上述两种方法都有明显的不足。 
对于第一种实现,内存被极大的浪费。 
对于第二种实现,如果GC还没有发生,此时员工信息的数据结构还留在内存中,然而却要重新创建一个一摸一样的数据结构。

这时,我们向往存在这样的一种引用,GC发生时,可以把这个引用解除并释放资源(注意,这种行为与上文所说的不会被GC回收掉的强引用是有区别的);而当GC未发生时,我们也很容易能重新获得这个对象。

为了产生具备这种特性的引用,就是设计软、弱、虚引用的目的。 下面详细介绍一下各种引用的不同点。

对象的强、软、弱、虚引用

强引用

强引用是最常见的引用,就如上文所列的: OneClass myClass = new OneClass();

如果一个对象(放在堆中的OneClass实例)具有强引用(放在栈中的myClass变量),那么这个对象就等若持有了免死金牌,GC绝不会回收它。

就算此时内存空间不足,JVM宁愿抛出一个OutOfMemory的错误使程序异常终止,也不会回收具备强引用的对象来解决内存不足的问题。

软引用

软引用是一种引用,它的创建及初始化方式与强引用不同。 
MyObject aRef = new MyObject(); 
SoftReference aSoftRef=new SoftReference(aRef); 

此时,aSoftRef就是指向MyObject实例的软引用。 注意,这个MyObject实例具备两个引用,一个是软引用aSoftRef,一个是强引用aRef。

随后再执行这条代码: aRef = null; 这么一来,MyObject实例只具备软引用。

如果一个对象只具有软引用,则当GC扫描到这个对象时,会根据当前内存情况来决定后续行为: 
1.内存空间充足,则GC不会回收它 。
2.内存空间不足,GC将回收它。

而只要GC没有回收它,这个对象就能被程序所使用(当然是通过aSoftRef来使用)。如果已经被回收,那么aSoftRef将会被JVM设置为null。

弱引用

弱引用的创建于软引用类似: 
MyObject aRef = new MyObject(); 
WeakReference aWeakRef=new WeakReference(aRef);

弱引用与软引用的区别在于,只要GC扫描到一个仅有弱引用的对象,那么无论当前内存情况如何,都会把它回收。不过,我们都知道GC线程的优先级很低,所以这样的对象不一定很快就会被回收掉。

虚引用

虚引用的创建: 
MyObject aRef = new MyObject(); 
PhantomReference aPhantomRef=new PhantomReference(aRef);

Phantom这个词直译成中文称为“幻象”,可以想见虚引用的虚无缥缈。如果一个对象仅持有虚引用,那么这个对象就如同没有任何引用一样,随时可能被GC收走。

虚引用主要用来跟踪对象被GC回收的过程。必须与引用队列(ReferenceQueue)联合使用。

总结

我们写Java代码时最常用的到的都是强引用,但是其他几种类型的引用会造成对象生命周期的不同。如果代码中出现了这些引用,我们需要特别留心,评估它们什么时候会被回收走。

  评论这张
 
阅读(257)| 评论(3)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016