文档章节

java基础之java.lang.ref.Reference

klink
 klink
发布于 2014/06/05 14:39
字数 1235
阅读 163
收藏 0

Reference

java.lang.ref类库主要作用在于当内存不足时,能够提醒gc,将一些使用ref定义的变量释放掉以缓解内存不足的压力。java.lang.ref.Reference有三种不同的子类,SoftReference,WeakReference以及PhantomReference。它们分成了三种不同的级别,gc会在不同的情况下一一释放它们引用对象的空间。

SoftReference

当我们希望对象的引用仍驻留在内存里面,直到内存出现不足时,gc会释放由SoftReference引用对象所占的内存空间。所以SoftReference可以用作Cache的实现。

 package io.github.klink;

// containers/References.java
// Demonstrates Reference objects
import java.lang.ref.*;
import java.util.*;

class VeryBig {
	private static final int SIZE = 10000;
	private long[] la = new long[SIZE];
	private String ident;
	public VeryBig(String id) { ident = id; }
	public String toString() { return ident; }
	protected void finalize() {
		System.out.println("Finalizing " + ident);
	}
}

public class References {
	private static ReferenceQueue<VeryBig> rq =
		new ReferenceQueue<VeryBig>();

	public static void checkQueue() {
		Reference<? extends VeryBig> inq = rq.poll();
		if(inq != null)
			System.out.println("In queue: " + inq.get());
	}

	public static void main(String[] args) {
		int size = 10;

		LinkedList<SoftReference<VeryBig>> sa =
			new LinkedList<SoftReference<VeryBig>>();

		for(int i = 0; i < size; i++) {
			sa.add(new SoftReference<VeryBig>(
					new VeryBig("Soft " + i), rq));
			System.out.println("Just created: " + sa.getLast());
			checkQueue();
		}

	System.gc();
	
	
	try {
		Thread.sleep(5000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	for(int i = 0; i < size; i++) {
		checkQueue();
	}

输出为:

Just created: java.lang.ref.SoftReference@5e1077
Just created: java.lang.ref.SoftReference@18b3364
Just created: java.lang.ref.SoftReference@1db05b2
Just created: java.lang.ref.SoftReference@530cf2
Just created: java.lang.ref.SoftReference@76fba0
Just created: java.lang.ref.SoftReference@181ed9e
Just created: java.lang.ref.SoftReference@1175422
Just created: java.lang.ref.SoftReference@949f69
Just created: java.lang.ref.SoftReference@16dadf9
Just created: java.lang.ref.SoftReference@1b8d6f7

WeakReference

WeakReference并不会影响其引用对象的生命周期。换句话说,如果该对象只被WeakReference引用的话,它仍然会被gc回收。但是在gc回收之前,WeakReference会普通的引用没有区别,都可以访问引用对象的成员。WeakReference可用于:一个对象可能会有若干的引用,当我们不清楚这些引用是否仍在的时候,可以通过WeakReference引用该对象,如果该对象仍在内存中的话,WeakReference就可以获取对象的值,如果不在的话,WeakReference将会为Null。

	LinkedList<WeakReference<VeryBig>> wa =
			new LinkedList<WeakReference<VeryBig>>();
	for(int i = 0; i < size; i++) {
		wa.add(new WeakReference<VeryBig>(
			new VeryBig("Weak " + i), rq));
		System.out.println("Just created: " + wa.getLast());
		checkQueue();
	}

	System.gc();
	
	
	try {
		Thread.sleep(5000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	for(int i = 0; i < size; i++) {
		checkQueue();
	}

输出结果为:

Just created: java.lang.ref.WeakReference@18b3364
Just created: java.lang.ref.WeakReference@1db05b2
Just created: java.lang.ref.WeakReference@530cf2
Just created: java.lang.ref.WeakReference@76fba0
Just created: java.lang.ref.WeakReference@181ed9e
Just created: java.lang.ref.WeakReference@1175422
Just created: java.lang.ref.WeakReference@949f69
Just created: java.lang.ref.WeakReference@16dadf9
Just created: java.lang.ref.WeakReference@1b8d6f7
Just created: java.lang.ref.WeakReference@290fbc
Finalizing Weak 9
Finalizing Weak 8
Finalizing Weak 7
Finalizing Weak 6
Finalizing Weak 5
Finalizing Weak 4
Finalizing Weak 3
Finalizing Weak 2
Finalizing Weak 1
Finalizing Weak 0
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null
In queue: null

PhantomReference

PhantomReference与WeakReference一样,不会影响其引用对象的生命周期。PhantomReference与前两个Reference不同的是,它并不会引用对象,(这就是为什么使用PhantomReference的get()方法总是返回null的原因)。我们从它的构造函数可以看到,它有两个参数其中一个是ReferenceQueue,在gc回收时,会将PhantomReference引用的对象插入到ReferenceQueue中。

但是在实际的代码执行过程中,并没有插入到ReferenceQueue,这点让我比较困惑。

	LinkedList<PhantomReference<VeryBig>> pa =
		new LinkedList<PhantomReference<VeryBig>>();
	for(int i = 0; i < size; i++) {
		pa.add(new PhantomReference<VeryBig>(
			new VeryBig("Phantom " + i), rq));
	System.out.println("Just created: " + pa.getLast());
	checkQueue();
	}
	
	System.gc();
	
	try {
		Thread.sleep(1000);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	for(int i = 0; i < size; i++) {
		checkQueue();
	}

输出结果为:

Just created: java.lang.ref.PhantomReference@5e1077
Just created: java.lang.ref.PhantomReference@18b3364
Just created: java.lang.ref.PhantomReference@1db05b2
Just created: java.lang.ref.PhantomReference@530cf2
Just created: java.lang.ref.PhantomReference@76fba0
Just created: java.lang.ref.PhantomReference@181ed9e
Just created: java.lang.ref.PhantomReference@1175422
Just created: java.lang.ref.PhantomReference@949f69
Just created: java.lang.ref.PhantomReference@16dadf9
Just created: java.lang.ref.PhantomReference@1b8d6f7
Finalizing Phantom 9
Finalizing Phantom 8
Finalizing Phantom 7
Finalizing Phantom 6
Finalizing Phantom 5
Finalizing Phantom 4
Finalizing Phantom 3
Finalizing Phantom 2
Finalizing Phantom 1
Finalizing Phantom 0

ReferenceQueue

每一个Reference的实现都会有一个构造函数需要ReferenceQueue作为参数。当Reference的子类绑定一个ReferenceQueue时,Reference所指向的对象一旦被gc回收,gc会再回收之前将对象插入到ReferenceQueue中。

WeakHashMap

WeakHashMap是基于WeakReference实现的一个Map。其特点是,WeakHashMap中的Key如果没有被任何对象引用的话,那么当gc回收垃圾的时候,这些未被引用的Key对应的记录会被删除。

package io.github.klink;

import java.util.*;

class Element {
	private String ident;
	public Element(String id) { ident = id; }
	public String toString() { return ident; }
	public int hashCode() { return ident.hashCode(); }

	public boolean equals(Object r) {
		return r instanceof Element &&
				ident.equals(((Element)r).ident);
	}

	protected void finalize() {
		System.out.println("Finalizing " +
				getClass().getSimpleName() + " " + ident);
	}
}

class Key extends Element {
	public Key(String id) { super(id); }
}

class Value extends Element {
	public Value(String id) { super(id); }
}

public class CanonicalMapping {
	public static void main(String[] args) {
		int size = 1000;
		// Or, choose size via the command line:

		Key[] keys = new Key[size];
		WeakHashMap<Key,Value> map =
				new WeakHashMap<Key,Value>();

		for(int i = 0; i < size; i++) {
			Key k = new Key(Integer.toString(i));
			Value v = new Value(Integer.toString(i));
			if(i % 3 == 0)
				keys[i] = k; // Save as "real" references
			map.put(k, v);
		}
		System.gc();
	}
} 

输出结果为:

Finalizing Key 98
Finalizing Key 625
Finalizing Key 683
Finalizing Key 733
Finalizing Key 779
Finalizing Key 811
Finalizing Key 856
Finalizing Key 901
Finalizing Key 944
Finalizing Key 977
Finalizing Key 998
Finalizing Key 997
Finalizing Key 995
Finalizing Key 994
Finalizing Key 992
Finalizing Key 991
Finalizing Key 989
Finalizing Key 988
Finalizing Key 986
Finalizing Key 985
Finalizing Key 983
Finalizing Key 982
Finalizing Key 980
Finalizing Key 979
Finalizing Key 976
Finalizing Key 974
Finalizing Key 973
Finalizing Key 971
Finalizing Key 970
Finalizing Key 968

© 著作权归作者所有

共有 人打赏支持
klink
粉丝 0
博文 24
码字总数 29450
作品 0
苏州
私信 提问
Java拾遗:005 - Java的四种引用类型

简介 Java中为了让程序员可以自己控制对象生命周期,提供了四种引用方式,都继承自类,它们分别是:强引用、软引用、弱引用、虚引用。 强引用(FinalReference / Finalizer) 在Java中像这种...

一别丶经年
2018/08/03
0
0
04《Java核心技术》之强引用、软引用、弱引用、幻象引用有什么区别?

一、提出问题 在 Java 语言中,除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象,理解引用对于掌握 Java 对象生命周期和 JVM 内部相关机制非常有帮助。 今天我们要...

飞鱼说编程
2018/09/17
0
0
JVM -verbose参数详解(转)

转自:http://www.javaranger.com/archives/367 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息。 1.java -verbose:class 在程序运行的时候有多少类被加载!你可以用verbose...

巴顿
2014/12/04
0
0
你所需要的java提升篇大总结

java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序的深入解析 java基础(五) Str...

sihailoveyan
2018/04/25
0
0
Java培训实战教程之Java基础知识精华部分(一)(二)(三)

Java培训实战教程之Java基础知识精华部分(一)_java概述 =============================================================================Java培训实战教程之Java基础知识精华部分(一)_java概...

黑泽明军
2018/04/13
0
0

没有更多内容

加载失败,请刷新页面

加载更多

虚拟化 - KVM 和 Xen 比较

Linux虚拟化技术的用户目前有两种免费的开源管理程序可以选择:Xen和KVM。 作为较早出现的虚拟化技术,Xen是“第一类”运行在裸机上的虚拟化管理程序(Hypervisor),也是当前相当一部分商业...

临江仙卜算子
30分钟前
1
0
给windows server中的“未识别的网络”或“无法识别的网络”设置网络位置类型

在windows server中,如果网络没有被正确的识别,那么就需要手工设置一下网络位置类型。 将“公用网络”指定设置为“专用网络“ 【控制面板】--【系统和安全】--【管理工具】--【本地安全策略...

gugudu
今天
2
0
阿里强制要求的21条Java开发规范,可以避免很多坑

1. 【强制】避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。 2. 【强制】所有的覆写方法,必须加@Override注解。 说明:getObject...

天王盖地虎626
今天
10
0
oracle dg 备库未设置convert参数导致ORA-01111,ORA-01110

查看trace 文件: MRP0: Background Managed Standby Recovery process started (amls) started logmerger process Sun Jan 20 07:55:53 2019 Managed Standby Recovery starting Real Time ......

hnairdb
今天
2
0
乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linux-tao
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部