文档章节

java基础之java.lang.ref.Reference

klink
 klink
发布于 2014/06/05 14:39
字数 1235
阅读 161
收藏 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中像这种...

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

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

飞鱼说编程
09/17
0
0
jstack和线程dump分析

一:jstack jstack命令的语法格式: jstack <pid>。可以用jps查看java进程id。这里要注意的是: 1. 不同的 JAVA虚机的线程 DUMP的创建方法和文件格式是不一样的,不同的 JVM版本, dump信息也...

xiaoxin
2013/12/30
0
1
JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52724939 JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千! 经过了几...

Aduroidpc
2016/10/02
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

没有更多内容

加载失败,请刷新页面

加载更多

探索802.11ax

802.11ax承诺在真实条件下改善峰值性能和最差情况。 如何改善今天的Wi-Fi? 在决定如何改进当前版本以外的Wi-Fi时,802.11ac,IEEE和Wi-Fi联盟调查了Wi-Fi部署和行为,以确定更广泛使用的障碍...

linuxprobe16
30分钟前
2
0
使用linux将64G的SDCARD格式化为FAT32

一、命令如下: sudo fdisk -lsudo mkfs.vfat /dev/sda -Isudo fdisk /dev/sda Welcome to fdisk (util-linux 2.29.2). Changes will remain in memory only, until you decide to wri......

mbzhong
今天
4
0
深入理解Plasma(四):Plasma Cash

这一系列文章将围绕以太坊的二层扩容框架,介绍其基本运行原理,具体操作细节,安全性讨论以及未来研究方向等。本篇文章主要介绍在 Plasma 框架下的项目 Plasma Cash。 深入理解Plasma(1):...

HiBlock
昨天
1
0
命令参数的三大风格:Posix、BSD、GNU

今天读到命令行中参数的风格有三大类,即Unix/Posix、BSD、GNU。分别有以下特征: Unix/Posix风格,即命令后的参数,可以分组,便必须以连字符开头,如ps -aux。 BSD风格,即命令后的参数,可...

大别阿郎
昨天
2
0
PHP生成图片验证码

PHP生成图片验证码 /** * PHP生成图片验证码 * Class VerifyImage */class VerifyImage{ // 生成随机字串 private $verifyCode; // 图片对象 private $image; /**...

DrChenXX
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部