垃圾回收是我们在学习java编程开发技术的时候需要重点掌握的技术能力之一,而今天我们就通过案例分析来学习一下java垃圾回收的引用与回收时间。
垃圾回收的基本思想是考察一个对象的可达性,即从根节点开始是否可以访问到这个对象,如果可以,则说明对象正在被使用,相反如果从根节点无法访问到这个对象,说明对象已经不再使用了,一般来说此对象就是需要被回收的。这个算法为根搜索算法。
可达性分析
但是实际中,一个不可达的对象有可能在某种条件下“复活”自己,那么对它的回收就是不合理的。为此给出一个对象可达性状态的定义,并规定了在什么状态下可以安全的回收对象。可达性对象包含了以下三种状态。
可达的:从根节点开始,按照引用节点,可以搜索到这个对象
可复活的:对象的所有引用都被释放,但是对象可能在finalize()方法中复活自己。
不可达的:对象的finalize()方法被调用,并且没有复活,那么就进入不可达状态。不可达的对象不可能会被“复活”,因为finalize()方法只能调用一次。
在JDK1.2之后对引用进行了扩充,分为强引用,软引用,弱引用,虚引用4种,这四种强度一次减弱。通过对引用的扩充,可以依据内存的使用来描述这样的对象:当内存足够,则保留内存中;如果内存空间进行垃圾回收后还是很紧张,则可以抛弃这类对象。很多系统的缓存功能符合这样的应用场景。
强引用
在Java中常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
软引用
软引用需要用SoftReference类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
弱引用
弱引用需要用WeakReference类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,总会回收该对象占用的内存。
虚引用
虚引用需要PhantomReference类来实现,它不能单独使用,必须和引用队列联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。
什时候回收
按HotSpotVM的serialGC的实现来看触发条件主要分为以下几种:
youngGC:当younggen中的eden区分配满的时候触发。注意youngGC中有部分存活对象会晋升到oldgen,所以youngGC后oldgen的占用量通常会有所升高。
fullGC:当准备要触发一次youngGC时,如果发现统计数据说之前youngGC的平均晋升大小比目前oldgen剩余的空间大,则不会触发youngGC而是转为触发fullGC(因为HotSpotVM的GC里,除了CMS的concurrentcollection之外,其它能收集oldgen的GC都会同时收集整个GC堆,包括younggen,所以不需要事先触发一次单独的youngGC);或者,如果有permgen的话,要在permgen分配空间但已经没有足够空间时,也要触发一次fullGC;或者System.gc()、heapdump带GC,默认也是触发fullGC。
HotSpotVM里其它非并发GC的触发条件复杂一些,不过大致的原理与上面说的其实一样。并发GC的触发条件就不太一样。以CMSGC为例,它主要是定时去检查oldgen的使用量,当使用量超过了触发比例就会启动一次CMSGC,对oldgen做并发收集。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!