Java -强引用&弱引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题.
使用强引用的一个例子。
图像缓存问题,图像缓存应该阻止我们重新载入图像,所以图像缓存保存有内存中已有的所有图像的引用,如果使用通常的强引用,强引用本身会使得图像一直存留在内存中,这样就使得程序员像上面一样,必须自己决定什么时候移除缓存中的引用,这样对象才能被垃圾回收机制回收。
当你想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候你就是用弱引用。这个引用不会影响gc对对象的回收。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
二、对象的可达性判断
在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图2所示

在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象5的路径就有①-⑤,③-⑦两条路径。由此带来了一个问题,那就是某个对象的可及性如何判断:
◆多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。
MyObject aRef = new MyObject();
SoftReference aSoftRef=new SoftReference(aRef);
此时,对于这个MyObject对象,有两个引用路径,一个是来自SoftReference对象的软引用,一个来自变量aReference的强引用,所以这个MyObject对象是强可及对象。
ReferenceQueue queue = new ReferenceQueue();
SoftReference ref=new SoftReference(aMyObject, queue);
那么当这个SoftReference所软引用的aMyOhject被垃圾收集器回收的同时,ref所强引用的SoftReference对象被列入ReferenceQueue(垃圾软引用)。也就是说,ReferenceQueue中保存的对象不是所有的Reference对象,而且是已经失去了它所软引用的对象的Reference对象。另外从ReferenceQueue这个名字也可以看出,它是一个队列,当我们调用它的poll()方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个Reference对象。
SoftReference ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
// 清除ref
}
package com.volshell.demo; import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Hashtable; /**
* @author volshell
* 以软引用的方式引用并存储对象(以对象为参数创建软引用)
* 在从软引用中获取对象 .get()
* 如果沒用从引用中获取对象,在这个时候再去创建一个对象,并将其建立引用。
* 如果在创建引用对象的时候创建了引用队列,使用get() = null 的时候,说明该对象已经被回收,那么这个软引用也没有存在的价值了
* 所以需要删除,需要一个适当的清除机制,避免大量SoftReference对象带来的内存泄漏。
*/
public class EmployeeCache {
static private EmployeeCache cache;// 一个Cache实例
private Hashtable<String, EmployeeRef> employeeRefs;// 用于Cache内容的存储
private ReferenceQueue<Employee> q;// 垃圾Reference的队列 // 继承SoftReference,使得每一个实例都具有可识别的标识。
// 并且该标识与其在HashMap内的key相同。
private class EmployeeRef extends SoftReference<Employee> {
private String _key = ""; public EmployeeRef(Employee em, ReferenceQueue<Employee> q) {
super(em, q);
_key = em.getId();
}
} // 构建一个缓存器实例
private EmployeeCache() {
employeeRefs = new Hashtable<String, EmployeeRef>();
q = new ReferenceQueue<Employee>();
} // 取得缓存器实例
public static EmployeeCache getInstance() {
if (cache == null) {
cache = new EmployeeCache();
}
return cache;
} // 以软引用的方式对一个Employee对象的实例进行引用并保存该引用
private void cacheEmployee(Employee em) {
cleanCache();// 清除垃圾引用
EmployeeRef ref = new EmployeeRef(em, q); //构建一个软引用
employeeRefs.put(em.getId(), ref);
} // 依据所指定的ID号,重新获取相应Employee对象的实例
public Employee getEmployee(String ID) {
Employee em = null;
// 缓存中是否有该Employee实例的软引用,如果有,从软引用中取得。
if (employeeRefs.containsKey(ID)) {
EmployeeRef ref = (EmployeeRef) employeeRefs.get(ID); // 获取软引用
em = (Employee) ref.get(); // 从软引用中获取实例
}
// 如果没有软引用,或者从软引用中得到的实例是null,重新构建一个实例,
// 并保存对这个新建实例的软引用
if (em == null) {
em = new Employee(ID);
System.out.println("Retrieve From EmployeeInfoCenter. ID=" + ID);
this.cacheEmployee(em);
}
return em;
} // 清除那些所软引用的Employee对象已经被回收的EmployeeRef对象
private void cleanCache() {
EmployeeRef ref = null;
while ((ref = (EmployeeRef) q.poll()) != null) {
employeeRefs.remove(ref._key);
}
} // 清除Cache内的全部内容
public void clearCache() {
cleanCache();
employeeRefs.clear();
System.gc();
System.runFinalization();
}
}
import java.util.WeakHashMap;
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 obj) {
return obj instanceof Element && ident.equals(((Element) obj).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=10;
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;
map.put(k, v);
}
System.gc();
}
}
输出结果
before gc
{8=8, 9=9, 4=4, 5=5, 6=6, 7=7, 0=0, 1=1, 2=2, 3=3}
after gc
{9=9, 6=6, 0=0, 3=3}
Finalizing Key 8
Finalizing Key 7
Finalizing Key 2
Finalizing Key 1
Java -强引用&弱引用的更多相关文章
- java当中的强引用,软引用,弱引用,虚引用
强引用,软引用,弱引用,虚引用:不同的引用类型主要体现在GC上 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收.即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryEr ...
- 理解Java中的弱引用(Weak Reference)
本篇文章尝试从What.Why.How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义.基本使用场景和使用方法.由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出, ...
- OC:面向对象的编程思想、基本的知识点总结、强,弱引用
OC 面向对象 和 面向过程 参考 面向过程:使用步骤划分功能,然后用函数一步一步的调用 面向对象:OOP (Object Oriented Programming) 使用功能来简化问题, 面向对象语 ...
- 你不可不知的Java引用类型之——弱引用
定义 弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型.在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收. 说明 弱 ...
- java强软弱虚引用详解(转载)
转载自:http://zhangjunhd.blog.51cto.com/113473/53092/ ava:对象的强.软.弱和虚引用 2007-12-01 17:20:20 标签:Java 软引用 ...
- C语言强、弱符号,强、弱引用
C语言强.弱符号,强.弱引用 符号定义 在编程中我们经常碰到符号重复定义的情况,当我们在同一个作用域内重复定义同一个变量时,有时是因为误写,有时是文件之间的冲突,编译器的处理方式就是报错: redef ...
- Java引用类型之弱引用与幻像引用
这一篇将介绍弱引用和幻像引用. 1.WeakReference WeakReference也就是弱引用,弱引用和软引用类似,它是用来描述"非必须"的对象的,它的强度比软引用要更弱一 ...
- Java 强引用 软引用 弱引用 虚引用详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt393 众所周知,java中是JVM负责内存的分配和回收,这是它的优点(使用方 ...
- java强引用 软引用 弱引用 虚引用
https://www.cnblogs.com/yw-ah/p/5830458.html Java四种引用包括强引用,软引用,弱引用,虚引用. 强引用: 只要引用存在,垃圾回收器永远不会回收Objec ...
随机推荐
- 《数字图像处理原理与实践(MATLAB版)》一书之代码Part6
本文系<数字图像处理原理与实践(MATLAB版)>一书之代码系列的Part6,辑录该书第281至第374页之代码,供有须要读者下载研究使用.代码运行结果请參见原书配图,建议下载代码前阅读下 ...
- android api 中文 (75)—— AdapterView.OnItemClickListener
前言 本章内容是android.widget.AdapterView.OnItemClickListener,版本为Android 2.3 r1,翻译来自"麦子",欢迎大家与他交流 ...
- 感觉挺有意思的SQL题目
1.有如下数据,要求查询每个班最低分和最高分,并将最高分与最低分显示为同一列 ID Student CourseName Score1 张三 English 802 张三 Math 703 张三 Ch ...
- js超简单日历
用原生js写了一个超级简单的日历.当做是练习js中的Date类型. 思路: 获取某个日期,根据年份计算出每个月的天数. 利用Date中的getDay()知道该月份的第一天为星期几. 循环创建表格,显示 ...
- 在后台获取Textarea控件的值
使用Request.Form方法 1.在前台设置name 属性 <textarea name="Content">hdjfhjdfhdj</textarea> ...
- 【前端】一句命令快速合并压缩 JS、CSS
引用自:一句命令快速合并 JS.CSS 在项目开发环境下,我们会把 JS 代码尽可能模块化,方便管理和修改,这就避免不了会出现一个项目自身 JS 文件数量达到10个或者更多. 而项目上线后,会要求将所 ...
- iOS开发中遇到的bug
报错:The operation couldn’t be completed. (LaunchServicesError error 0.) 解决办法:重置模拟器
- js this [转]
this是js的一个关键字,随着函数使用场合不同,this的值会发生变化.但是总有一个原则,那就是this指的是调用函数的那个对象. 1.纯粹函数调用. function test() { this. ...
- 快速提取PROTEL99SE PCB文件上的封装方法
1.首先打开你要提取元件封装的PCB. 2.执行生成元件库的命令...软件会帮你把这个PCB上的所有元件生成一个临时库. 3.打开你自己的元件库... 4.PCB刚才生成的元件库中选中你所需要的元件, ...
- cocos2dx进阶学习之屏幕适配
背景 在学习cocos2dx时,我们在main函数中发现一句代码, #include "main.h" #include "AppDelegate.h" #in ...