Java一共有四种不同的引用类型,主要体现的是对象不同的可达性状态和对垃圾收集的影响。
1. 强引用
所谓强引用就是我们最常见的普通对象引用,只要还有强对象引用指向一个对象,就能表明该对象还活着,垃圾收集器不会碰这种对象。对于一个普通的对象,如果没有其他引用关系,只要超过了引用的作用域或者显示的将相应(强)引用赋值为null,就是可以被垃圾收集的了,当然具体回收时机还是要看垃圾回收策略。
public static void main(String[] args) throws InterruptedException {
//user1会超过作用域
{
User user1=new User("u1");
}
//user2显示的将强引用赋null
User user2=new User("u2");
user2=null;
User user3=new User("u3");
System.gc();
Thread.sleep(5000);
}
2. 软引用(SoftRefrence)
软引用是一种相对弱化一点的强引用,可以让对象豁免一些垃圾收集,只有当JVM认为内存不够时,才会对该引用指向的对象进行垃圾回收。JVM会确保在抛出OOM之前进行软引用对象的回收。软引用通常用来实现内存敏感的缓存。
public static void main(String[] args) throws InterruptedException {
User user=new User("张三");
SoftReference<User> soft=new SoftReference<User>(user);
user=null;
System.gc();
/*
* soft.get() @return The object to which this reference refers,
* or null if this reference object has been cleared
*/
if(soft.get()==null) {
System.out.println("软引用对象已经被清理,此时没有引用指向User对象");
}else {
System.out.println("name:"+soft.get().getName());
}
}
3. 弱引用(WeakRefrence)
弱引用不会使对象豁免垃圾收集,仅仅是提供一种访问在弱引用状态下对象的途径。这就可以用来构建一种没有特定约束的关系,比如,维护一种非强制性的映射关系,如果试图获取时对象还在,就使用它,否则重新实例化。
//弱引用
User user=new User("张三");
WeakReference<User> weak=new WeakReference<User>(user);
user=null;
//System.gc();
if(weak.get()==null) {
System.out.println("弱引用对象已经被清理,此时没有引用指向User对象");
}else {
System.out.println("name:"+weak.get().getName());
}
4. 幻象引用(PhantomReference)
幻象引用主要用来跟踪对象被垃圾回收器回收的活动。幻象引用与软引用和弱引用的一个区别在于:幻象引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有幻象引用,就会在回收对象的内存之前,把这个幻象引用加入到与之 关联的引用队列中。
User user=new User("张三",12);
ReferenceQueue queue=new ReferenceQueue();
PhantomReference<User> phantomRef=new PhantomReference<User>(user,queue);
user=null;
显示的影响软引用垃圾收集:
软引用通常会在最后一次引用后,还能保持一段时间,默认值是根据堆剩余空间计算的(以M bytes为单位)。从Java1.3.1开始,提供了-XX:SoftRefLRUPolicyMSPerMB参数,我们可以以毫秒(milliseconds)为单位设置。比如,下面这个示例就是设置为3秒。
-XX:SoftRefLRUPolicyMSPerMB=3000
这个剩余空间,其实会受到不同JVM模式的影响,对于Client模式,比如通常的Windows32 bit JDK,剩余空间是计算当前堆里的空闲的大小,所以更加倾向于回收;而对于server模式JVM,则是根据-Xmx指定的最大值来计算。
诊断JVM引用情况(Java8中):
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintReferenceGC
Reachability fence,在Java9中使用reachabilityFence达到强引用的效果:
class Resource {
private static ExternalResource[] externalResourceArray = ...
int myIndex; Resource(...) {
myIndex = ...
externalResourceArray[myIndex] = ...;
...
}
protected void finalize() {
externalResourceArray[myIndex] = null;
...
}
public void action() {
try {
// 需要被保护的代码
int i = myIndex;
Resource.update(externalResourceArray[i]);
} finally {
// 调用 reachbilityFence,明确保障对象 strongly reachable
Reference.reachabilityFence(this);
}
}
private static void update(ExternalResource ext) {
ext.status = ...;
}
}