文档章节

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核心技术36讲》之强引用、软引用、弱引用、幻象引用有什么区别?

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

飞鱼说编程
09/17
0
0
JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千!

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

Aduroidpc
2016/10/02
0
0
jstack和线程dump分析

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

xiaoxin
2013/12/30
0
1
JVM -verbose参数详解(转)

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

巴顿
2014/12/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

ehlib 修改 使行号字体颜色 与标题字体颜色 一致

对ehlib 显示效果不够满意,而做的调整 修改这个过程:procedure TCustomDBGridEh.DrawIndicatorCell(ACol, ARow: Longint; AreaCol, AreaRow: Longint; ARect: TRect; AState: TGri......

vga
27分钟前
0
0
Bash重定向详解

Bash重定向详解 Bash的重定向指的是将命令的输入和输出导向不同地方,而不是默认的标准输入、标准输出和标准错误。Bash的重定向实际上是对标准输入、标准输出和标准错误的重置,进而将所需输...

小陶小陶
今天
3
0
EventBus原理深度解析

一、问题描述 在工作中,经常会遇见使用异步的方式来发送事件,或者触发另外一个动作:经常用到的框架是MQ(分布式方式通知)。如果是同一个jvm里面通知的话,就可以使用EventBus。由于Event...

yangjianzhou
今天
19
0
OpenCV图像处理实例:libuv+cvui显示摄像头视频

#include <iostream>#include <opencv2/opencv.hpp>#define CVUI_IMPLEMENTATION#include <cvui.h>extern "C"{#include <uv.h>}using namespace std;#define WINDOW_NAM......

IOTService
今天
4
0
openJDK之JDK9的String

1.openJDK8的String 先来看下openJDK8的String的底层,如下图1.1所示: 图1.1 底层上使用的是char[],即char数组 每个char占16个bit,Character.SIZE的值是16。 2.openJDK9中的String 图2.1...

克虏伯
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部