Java从1.2版本开始引入了4种引用,这4种引用的级别由高到低依次为:
强引用 > 软引用 > 弱引用 > 虚引用
⑴强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
⑵软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
⑶弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
⑷虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
由于引用和内存回收关系紧密。下面,先通过实例对内存回收有个认识;然后,进一步通过引用实例加深对引用的了解。
我们首先来建立一个类:
public
class
MyDate
extends
Date{
public
MyDate(){
}
//我们来重写finalize,因为finalize函数 在JvM回收内存的时候会调用,但是JVM并不保证回收的时候一定会调用
@Override
protected
void
finalize()
throws
Throwable {
super
.finalize();
System.
out
.println(
this
.getTime());
}
@Override
public
String toString() {
return
"Date"
+
this
.getTime();
}
}
再来建立一个消耗内存的测试类
public
class
ReferenceTest {
public
ReferenceTest(){
}
//这个方法的目的是来消耗内存
public
static
void
drainMemory(){
String array[]=
new
String[1024*10];
for
(
int
i=0;i<1024*10;i++){
for
(
int
j=
'a'
;j<
'z'
;j++){
array[i]=array[i]+(
char
)j;
}
}
}
}
我们下面来分情况来测试一下
1.清除对象
public
class
Test {
public
static
void
main(String[] args) {
MyDate myDate=
new
MyDate();
myDate=
null
;
}
}
结果无输出
说明date=null,但是JVM并没有执行垃圾回收操作
2.显示的调用垃圾回收
public
class
Test {
public
static
void
main(String[] args) {
MyDate myDate=
new
MyDate();
myDate=
null
;
System. gc();//设为空后,去自动调用垃圾回收
}
}
结果:
1386430828594
说明垃圾回收机制调用了finalize()方法
3.隐式的调用垃圾回收
public
class
Test {
public
static
void
main(String[] args) {
MyDate myDate=
new
MyDate();
myDate=
null
;
ReferenceTest. drainMemory();
//我们来造成内存的大量消耗
}
}
结果:
1386431068074
说明调用了垃圾回收机制(内存的大量消耗造成了垃圾回收自动调用),我们得出结论,在内存充足的情况下,除非你显示的调用垃圾回收机制,否则它不会进行垃圾回收,在内存不足的情况下,JVM会自动调用垃圾回收
我们在来看看java对引用的分类
强引用:
public
class
Test {
public
static
void
main(String[] args) {
MyDate myDate=
new
MyDate();//强引用
System. gc();
}
}
结果:
无输出,说明虽然我们显示的调用了垃圾回收,但是mydate是强引用,所以不会被回收
软引用
public
class
Test {
public
static
void
main(String[] args) {
SoftReference ref =
new
SoftReference(
new
MyDate());
//创建一个软引用
ReferenceTest. drainMemory();
}
}
结果无所出:
说明在内存不足的情况下,软引用会被停止
弱引用:
public
class
Test {
public
static
void
main(String[] args) {
WeakReference ref =
new
WeakReference(
new
MyDate());
ReferenceTest. drainMemory();
}
}
结果:
1386431868012
说明在J垃圾回收的时候,弱引用被停止
虚引用:
public
class
Test {
public
static
void
main(String[] args) {
ReferenceQueue queue=
new
ReferenceQueue();
PhantomReference ref =
new
PhantomReference(
new
MyDate(), queue);
//ReferenceTest.drainMemory();
System.gc();
}
}
结果:
1386432527842
说明对象在创建完成之后,就被垃圾回收了