- 浏览: 213769 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
strong8808:
activemq5.8.0 客户端,服务端启动序列图 -
xurichusheng:
第一题,如果使用 not exists 的话,可以改成:SEL ...
SQL笔试题 -
dingjun1:
cuisuqiang 写道如何解决呢?我的是对了也照样缓存增加 ...
事务未正确关闭引起的HIBERNATE SESSION不能正确关闭 -
dingjun1:
aijezdm915 写道lz ,我也是在写项目描述是犯愁,能 ...
如果在简历中描述项目 -
aijezdm915:
lz ,我也是在写项目描述是犯愁,能否给个你的简历demo,我 ...
如果在简历中描述项目
转载:http://blog.csdn.net/xtyyumi301/archive/2008/10/04/3015493.aspx
Understanding Weak References
以前我招聘过高级java工程师,其中一个面试题目是“你对weak reference了解多少?”。这个话题比较偏,不指望每个人都能清楚它的细节。如果面试的人说“Umm...好像和gc(垃圾回收)有点关系?”,那我就相当满意了。实际情况却是20多个5年java开发经验的工程师只有2个知道有weak reference这么回事,其中1个是真正清楚的。我试图给他们一些提示,期望有人会恍然大悟,可惜没有。不知道为什么这个特性uncommon,确切地说,是相当uncommon,要知道这是在java1.2中推出的,那是7年前的事了。
没必要成为weak reference专家,装成资深java工程师(就像茴香豆的茴字有四种写法)。但是至少要了解一点点,知道是怎么回事。下面告诉你什么是weak references,怎么用及何时用它们。
l Strong references
从强引用(Strong references)开始。你每天用的就是strong reference,比如下面的代码:StringBuffer buffer = new StringBuffer();创建了一个StringBuffer对象,变量buffer保存对它的引用。这太小儿科了!是的,请保持点耐心。Strong reference,是什么使它们‘strong’?——是gc处理它们的方式:如果一个对象通过一串强引用链可达,那么它们不会被垃圾回收。你总不会喜欢gc把你正在用的对象回收掉吧。
l When strong references are too strong
我们有时候用到一些不能修改也不能扩展的类,比如final class,再比如,通过Factory创建的对象,只有接口,连是什么实现都不知道。想象一下,你正在用widget类,需要知道每个实例的扩展信息,比如它是第几个被创建的widget实例(即序列号),假设条件不允许在类中添加方法,widget类自己也没有这样的序列号,你准备怎么办?用HashMap!serialNumberMap.put(widget, widgetSerialNumber),用变量记录新实例的序列号,创建实例时把实例和它的序列号放到HashMap中。很显然,这个Map会不断变大,从而造成内存泄漏。你要说,不要紧,在不用某个实例时就从map中删除它。是的,这可行,但是“put——remove”,你不觉得你在做与内存管理“new——delete”类似的事吗?像所有自己管理内存的语言一样,你不能有遗漏。这不是java风格。
另一个很普遍的问题是缓存,特别是很耗内存的那种,比如图片缓存。想象一下,有个项目要管理用户自己提供的图片,比如像我正在做的网站编辑器。自然地你会把这些图片缓存起来,因为每次从磁盘读取会很耗时,而且可以避免在内存中一张图片出现多份。你应该能够很快地意识到这有内存危机:由于图片占用的内存没法被回收,内存迟早要用完。把一部分图片从缓存中删除放到磁盘上去!——这涉及到什么时候删除、哪些图片要删除的问题。和widget类一样,不是吗,你在做内存管理的工作。
l Weak reference
Weak reference,简单地说就是这个引用不会强到迫使对象必须保持在内存中。Gc不会碰Strong reference可达的对象,但可以碰weak reference可达的对象。下面创建一个weak reference:WeakReference weakWidget = new WeakReference(widget),使用weakWidget.get()来取到widget对象。注意,get()可能返回null。什么?null?什么时候变成null了?——当内存不足垃圾回收器把widget回收了时(如果是Strong reference,这是不可能发生的)。你会问,变成null之后要想再得到widget怎么办?答案是没有办法,你得重新创建widget对象,对cache系统这很容易做到,比如图片缓存,从磁盘载入图片即可(内存中的每份图片要在磁盘上保存一份)。
像上面的“widget序列号”问题,最简单的是用jdk内含的WeakHashMap类。WeakHashMap和HashMap的工作方式类似,不过它的keys(注意不是values)都是weak reference。如果WeakHashMap中的一个key被垃圾回收了,那么这个entry会被自动删除。如果使用的是Map接口,那么实例化时只需把HashMap改成WeakHashMap,其它代码都不用变,就这么简单。
l Reference queque
一旦WeakReference.get()返回null,它指向的对象被垃圾回收,WeakReference对象就一点用都没有了,如果要对这些没有的WeakReference做些清理工作怎么办?比如在WeakHashMap中要把回收过的key从Map中删除掉。jdk中的ReferenceQueue类使你可以很容易地跟踪dead references。WeakReference类的构造函数有一个ReferenceQueue参数,当指向的对象被垃圾回收时,会把WeakReference对象放到ReferenceQueue中。这样,遍历ReferenceQueue可以得到所有回收过的WeakReference。WeakHashMap的做法是在每次调用size()、get()等操作时都先遍历ReferenceQueue,处理那些回收过的key,见jdk的源码WeakHashMap# expungeStaleEntries()。
l Different degrees of weakness
上面我们仅仅提到“weak reference”,实际上根据弱的层度不同有四种引用:强(strong)、软(soft)、弱(weak)、虚(phantom)。我们已经讨论过strong和weak,下面看下soft和phantom。
n Soft reference
Soft reference和weak reference的区别是:一旦gc发现对象是weak reference可达就会把它放到ReferenceQueue中,然后等下次gc时回收它;当对象是Soft reference可达时,gc可能会向操作系统申请更多内存,而不是直接回收它,当实在没辙了才回收它。像cache系统,最适合用Soft reference。
n Phantom reference
虚引用Phantom reference与Soft reference和WeakReference的使用有很大的不同:它的get()方法总是返回null(不信可以看jdk的PhantomReference源码)。这意味着你只能用PhantomReference本身,而得不到它指向的对象。它的唯一用处是你能够在ReferenceQueue中知道它被回收了。为何要有这种“不同”?
何时进入ReferenceQueue产生了这种“不同”。WeakReference是在它指向的对象变得弱可达(weakly reachable)时立即被放到ReferenceQueue中,这在finalization、garbage collection之前发生。理论上,你可以在finalize()方法中使对象“复活”(使一个强引用指向它就行了,gc不会回收它),但WeakReference已经死了(死了?不太明白作者的确切意思。在finalize中复活对象不太能够说明问题。理论上你可以复活ReferenceQueue中的WeakReference指向的对象,但没法复活PhantomReference指向的对象,我想这才是它们的“不同”)。而PhantomReference不同,它是在garbage collection之后被放到ReferenceQueue中的,没法复活。
PhantomReferences的价值在哪里?我只说两点:1、你能知道一个对象已经从内存中删除掉了,事实上,这是唯一的途径。这可能不是很有用,只能用在某些特别的场景中,比如维护巨大的图片:只有图片对象被回收之后才有必要再载入,这在很大程度上可以避免OutOfMemoryError。2、可以避免finalize()方法的缺点。在finalize方法中可以通过新建强引用来使对象复活。你可能要说,那又怎么样?——finalize的问题是对那些重载了finalize方法的对象垃圾回收器必须判断两遍才能决定回收它。第一遍,判断对象是否可达,如果不可达,看是否有finalization,如果有则调用,否则回收;第二遍判断对象是否可达,如果不可达,则回收。由于finalize是在内存回收之前调用的,那么在finalize中可能出现OutOfMemoryError,即使很多对象可以被回收。用PhantomReference就不会出现这种情况,当PhantomReference进入ReferenceQueue之后就没法再获得所指向的对象(它已经从内存中删除了)。由于PhantomReference不能使对象复活,所以它指向的对象可以在第一遍时回收,有finalize方法的对象就不行。可以证明,finalize方法不是首选。PhantomReference更安全更有效,可以简化VM的工作。虽然好处多,但要写的代码也多。所以我坦白承认,大部分情况我还是用finalize。不管怎么样,你多了个选择,不用在finalize这棵树上吊死。
l 总结
我打赌有人在嘟囔,说我在讲老黄历,没什么鲜货。你说得没错,不过,以我的经验仍有很多java工程师对weak reference没甚了解,这样一堂入门课对他们很有必要。真心希望你能从这篇文章中得到一点收获。
Understanding Weak References
以前我招聘过高级java工程师,其中一个面试题目是“你对weak reference了解多少?”。这个话题比较偏,不指望每个人都能清楚它的细节。如果面试的人说“Umm...好像和gc(垃圾回收)有点关系?”,那我就相当满意了。实际情况却是20多个5年java开发经验的工程师只有2个知道有weak reference这么回事,其中1个是真正清楚的。我试图给他们一些提示,期望有人会恍然大悟,可惜没有。不知道为什么这个特性uncommon,确切地说,是相当uncommon,要知道这是在java1.2中推出的,那是7年前的事了。
没必要成为weak reference专家,装成资深java工程师(就像茴香豆的茴字有四种写法)。但是至少要了解一点点,知道是怎么回事。下面告诉你什么是weak references,怎么用及何时用它们。
l Strong references
从强引用(Strong references)开始。你每天用的就是strong reference,比如下面的代码:StringBuffer buffer = new StringBuffer();创建了一个StringBuffer对象,变量buffer保存对它的引用。这太小儿科了!是的,请保持点耐心。Strong reference,是什么使它们‘strong’?——是gc处理它们的方式:如果一个对象通过一串强引用链可达,那么它们不会被垃圾回收。你总不会喜欢gc把你正在用的对象回收掉吧。
l When strong references are too strong
我们有时候用到一些不能修改也不能扩展的类,比如final class,再比如,通过Factory创建的对象,只有接口,连是什么实现都不知道。想象一下,你正在用widget类,需要知道每个实例的扩展信息,比如它是第几个被创建的widget实例(即序列号),假设条件不允许在类中添加方法,widget类自己也没有这样的序列号,你准备怎么办?用HashMap!serialNumberMap.put(widget, widgetSerialNumber),用变量记录新实例的序列号,创建实例时把实例和它的序列号放到HashMap中。很显然,这个Map会不断变大,从而造成内存泄漏。你要说,不要紧,在不用某个实例时就从map中删除它。是的,这可行,但是“put——remove”,你不觉得你在做与内存管理“new——delete”类似的事吗?像所有自己管理内存的语言一样,你不能有遗漏。这不是java风格。
另一个很普遍的问题是缓存,特别是很耗内存的那种,比如图片缓存。想象一下,有个项目要管理用户自己提供的图片,比如像我正在做的网站编辑器。自然地你会把这些图片缓存起来,因为每次从磁盘读取会很耗时,而且可以避免在内存中一张图片出现多份。你应该能够很快地意识到这有内存危机:由于图片占用的内存没法被回收,内存迟早要用完。把一部分图片从缓存中删除放到磁盘上去!——这涉及到什么时候删除、哪些图片要删除的问题。和widget类一样,不是吗,你在做内存管理的工作。
l Weak reference
Weak reference,简单地说就是这个引用不会强到迫使对象必须保持在内存中。Gc不会碰Strong reference可达的对象,但可以碰weak reference可达的对象。下面创建一个weak reference:WeakReference weakWidget = new WeakReference(widget),使用weakWidget.get()来取到widget对象。注意,get()可能返回null。什么?null?什么时候变成null了?——当内存不足垃圾回收器把widget回收了时(如果是Strong reference,这是不可能发生的)。你会问,变成null之后要想再得到widget怎么办?答案是没有办法,你得重新创建widget对象,对cache系统这很容易做到,比如图片缓存,从磁盘载入图片即可(内存中的每份图片要在磁盘上保存一份)。
像上面的“widget序列号”问题,最简单的是用jdk内含的WeakHashMap类。WeakHashMap和HashMap的工作方式类似,不过它的keys(注意不是values)都是weak reference。如果WeakHashMap中的一个key被垃圾回收了,那么这个entry会被自动删除。如果使用的是Map接口,那么实例化时只需把HashMap改成WeakHashMap,其它代码都不用变,就这么简单。
l Reference queque
一旦WeakReference.get()返回null,它指向的对象被垃圾回收,WeakReference对象就一点用都没有了,如果要对这些没有的WeakReference做些清理工作怎么办?比如在WeakHashMap中要把回收过的key从Map中删除掉。jdk中的ReferenceQueue类使你可以很容易地跟踪dead references。WeakReference类的构造函数有一个ReferenceQueue参数,当指向的对象被垃圾回收时,会把WeakReference对象放到ReferenceQueue中。这样,遍历ReferenceQueue可以得到所有回收过的WeakReference。WeakHashMap的做法是在每次调用size()、get()等操作时都先遍历ReferenceQueue,处理那些回收过的key,见jdk的源码WeakHashMap# expungeStaleEntries()。
l Different degrees of weakness
上面我们仅仅提到“weak reference”,实际上根据弱的层度不同有四种引用:强(strong)、软(soft)、弱(weak)、虚(phantom)。我们已经讨论过strong和weak,下面看下soft和phantom。
n Soft reference
Soft reference和weak reference的区别是:一旦gc发现对象是weak reference可达就会把它放到ReferenceQueue中,然后等下次gc时回收它;当对象是Soft reference可达时,gc可能会向操作系统申请更多内存,而不是直接回收它,当实在没辙了才回收它。像cache系统,最适合用Soft reference。
n Phantom reference
虚引用Phantom reference与Soft reference和WeakReference的使用有很大的不同:它的get()方法总是返回null(不信可以看jdk的PhantomReference源码)。这意味着你只能用PhantomReference本身,而得不到它指向的对象。它的唯一用处是你能够在ReferenceQueue中知道它被回收了。为何要有这种“不同”?
何时进入ReferenceQueue产生了这种“不同”。WeakReference是在它指向的对象变得弱可达(weakly reachable)时立即被放到ReferenceQueue中,这在finalization、garbage collection之前发生。理论上,你可以在finalize()方法中使对象“复活”(使一个强引用指向它就行了,gc不会回收它),但WeakReference已经死了(死了?不太明白作者的确切意思。在finalize中复活对象不太能够说明问题。理论上你可以复活ReferenceQueue中的WeakReference指向的对象,但没法复活PhantomReference指向的对象,我想这才是它们的“不同”)。而PhantomReference不同,它是在garbage collection之后被放到ReferenceQueue中的,没法复活。
PhantomReferences的价值在哪里?我只说两点:1、你能知道一个对象已经从内存中删除掉了,事实上,这是唯一的途径。这可能不是很有用,只能用在某些特别的场景中,比如维护巨大的图片:只有图片对象被回收之后才有必要再载入,这在很大程度上可以避免OutOfMemoryError。2、可以避免finalize()方法的缺点。在finalize方法中可以通过新建强引用来使对象复活。你可能要说,那又怎么样?——finalize的问题是对那些重载了finalize方法的对象垃圾回收器必须判断两遍才能决定回收它。第一遍,判断对象是否可达,如果不可达,看是否有finalization,如果有则调用,否则回收;第二遍判断对象是否可达,如果不可达,则回收。由于finalize是在内存回收之前调用的,那么在finalize中可能出现OutOfMemoryError,即使很多对象可以被回收。用PhantomReference就不会出现这种情况,当PhantomReference进入ReferenceQueue之后就没法再获得所指向的对象(它已经从内存中删除了)。由于PhantomReference不能使对象复活,所以它指向的对象可以在第一遍时回收,有finalize方法的对象就不行。可以证明,finalize方法不是首选。PhantomReference更安全更有效,可以简化VM的工作。虽然好处多,但要写的代码也多。所以我坦白承认,大部分情况我还是用finalize。不管怎么样,你多了个选择,不用在finalize这棵树上吊死。
l 总结
我打赌有人在嘟囔,说我在讲老黄历,没什么鲜货。你说得没错,不过,以我的经验仍有很多java工程师对weak reference没甚了解,这样一堂入门课对他们很有必要。真心希望你能从这篇文章中得到一点收获。
发表评论
-
jstatd jsp 等不能正常运行的原因
2013-12-11 11:04 634[root@ bin]# ./jstatd Could not ... -
jvm信息查看
2013-06-03 08:28 7621、查看当前服务的cpu 、内存、磁盘等使用情况,看看是不是使 ... -
Paxos算法深入分析
2012-12-12 20:21 1053转载: http://blog.sina.com.cn/s/b ... -
Unveiling the java.lang.Out OfMemoryError
2011-04-13 19:02 908Unveiling the java.lang.Out OfM ... -
getOutputStream() has already been called for this response异常的原因和解决方法
2010-11-27 14:32 862getOutputStream() has already b ... -
servlet filter url-pattern
2010-10-28 09:47 1301ApplicationFilterFactory: /** ... -
JVM内存
2010-09-26 16:03 1017转载:http://blog.csdn.net/c ... -
java nio 笔记
2010-08-19 20:16 1976一、基础知识 操作系统 ... -
集合框架
2010-08-04 22:09 865集合框架: BitSet:??? Ha ... -
基本数据结构介绍
2010-08-01 18:22 943二叉查找树: 性质:设x为二叉查找树中的一个结点。如果y是x的 ... -
设置SESSION超时时间
2010-07-02 15:07 1471设置session时间的3个方法: 1. 在tomcat--c ... -
垃圾收集机制
2010-04-23 16:49 813转载:http://tech.ccidnet.com/art ... -
JAVA语言细节总结
2010-04-17 12:47 8661、java 源代码文件通常称为一个编译单元,每个编译单元内最 ... -
utf8的编码原理
2009-07-20 15:08 1156大概意思: 在UTF8中,字符使用1到6个八位序列编码。 只有 ... -
转发(forward)、包含(include)及转向(redirect)的区别与联系
2009-07-17 15:57 982转发(forward)、包含(include)及转向(redi ... -
对数运算公式
2009-07-03 16:15 2156附件二为自然对数的介绍PPT -
二叉树相关知识
2009-07-03 16:04 946一、二叉树的构建与打印 Node.java publ ... -
ThreadLocal的几种误区
2009-06-26 10:48 836转载:http://www.blogjava.ne ... -
JAR打包
2009-03-13 15:38 1001在CMD下,当我们敲下jar -help时,系统给我们提供了如 ... -
JAVA正则表达式
2009-03-02 18:32 1292正则表达式 常用语法 正则表达式的构造字符 匹配 X 字符X ...
相关推荐
在C语言中,我们并没有直接的`weak`关键字,但可以通过其他方式模拟弱引用。例如,可以使用指针间接引用对象,而不增加其引用计数。在C++或Objective-C中,`weak`属性则是一个标准的特性,它允许创建一个不增加对象...
本篇文章尝试从What、Why、How这三个角度来探索Java中的弱引用,理解Java中弱引用的定义、基本使用场景和使用方法。由于个人水平有限,叙述中难免存在不准确或是不清晰的地方,希望大家可以指出,谢谢大家:) 1....
在这个过程中,软引用(Soft Reference)和弱引用(Weak Reference)是两种非常重要的工具,它们可以帮助我们避免内存泄漏,提高应用的内存效率。下面我们将深入探讨这两种引用类型及其在Android中的应用。 首先,...
从JDK 1.2版本开始,Java引入了四种不同级别的引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)。这些引用类型提供了灵活的内存管理策略,允许...
在Java中,`java.lang.ref`包提供了三种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)和弱引用(Weak Reference)。我们主要关注弱引用,它通过`WeakReference`类来实现。弱引用对象在创建...
在上面的代码中,我们定义了两个类 A 和 B,类 A 有一个私有字符串域 name,类 B 有一个私有字符串域 name 和一个弱引用 weak_a 指向类 A 的对象。我们可以看到,在 testCommon 方法中,我们首先创建了一个类 A 的...
VSoft.WeakReference 该单元背后的思想是提供与Delphi中引用计数对象类似的生命周期...可以弱引用的类需要从TWeakReferencedObject 。 type TParent = class(TWeakReferencedObject, IParent) ... end; TChild =
3. **弱引用(Weak Reference)**: - 弱引用比软引用更弱,只要垃圾收集器运行,无论内存是否充足,都会回收弱引用指向的对象。弱引用常用于实现内存敏感的缓存。 - 示例:`WeakReference<String> weakRef = new ...
3. 弱引用(Weak Reference) 弱引用比软引用的生存期更短。一旦创建了弱引用,那么无论系统内存是否充足,只要进行垃圾回收,就会回收弱引用指向的对象。弱引用通常用于避免内存泄漏,特别是在那些对象不再需要,...
自引入 ARC(Automatic Reference Counting)以来,Objective-C 的内存管理变得更加便捷,但仍需要理解其背后的原理,尤其是在使用弱引用时。 #### 一、弱引用的概念 弱引用是一种特殊的引用类型,在 Objective-C ...
弱引用(WeakReferences)是现代编程语言中一种优雅的机制,它允许应用程序与垃圾收集器(GarbageCollector)进行交互。在自动内存管理的编程语言中,通常会提供一套接口,以允许客户端程序与垃圾收集器交互。这些...
2. **weak_table_t**:全局弱引用的哈希表,用于存储`weak_entry_t`结构体,其成员包括`weak_entries`(指向弱引用条目的指针)、`num_entries`(条目数量)、`mask`(参与哈希计算的掩码)和`max_hash_displacement...
它允许定义一个可替换的全局变量或函数,如果在链接阶段有更强的定义(非弱引用),则弱引用会被覆盖,否则弱引用的定义将被使用。这种机制在某些特定情况下的软件设计中非常有用,例如库的默认实现、驱动程序的可...
其次,弱引用(Weak References)比软引用更弱,它完全不会影响对象的生命周期。持有弱引用的对象可以在任何时候被垃圾收集器清理,即使存在弱引用。弱引用主要用于那些不希望影响对象生命周期,但又需要在某些时刻...
2. **弱引用(Weak Reference)** - **定义**:弱引用不会阻止对象被垃圾收集。一旦所有强引用消失,即使有弱引用指向,对象也会被回收。 - **例子**:`WeakReference<Object> weakRef = new WeakReference(new ...
本文将深入探讨Java中三种特殊的引用类型——软引用(Soft Reference)、弱引用(Weak Reference)以及虚引用(Phantom Reference),并分析它们如何帮助我们更好地管理内存资源。 #### 二、基础知识回顾 在深入了解这三...
3. **弱引用(Weak Reference)**: - 弱引用比软引用更弱,它不会阻止对象被垃圾收集。通过`java.lang.ref.WeakReference`类创建。只要发现对象只有弱引用,JVM就会在下一次GC时回收该对象。弱引用适用于那些...
为了更好地理解和控制对象的生命周期,Java提供了四种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)以及虚引用(Phantom Reference)。每种引用都有其特定的...
为了解决这一问题,Lua提供了一种机制,即弱引用(weak references)。 弱引用是允许引用对象,但是这些引用并不阻止对象被垃圾收集器回收。在Lua中,弱引用通常用于实现缓存机制或使某些对象与生命周期更长的其他...
在本教程中,我们将探讨如何利用这个机制来实现一个基于弱引用的计时器,以避免内存泄漏的问题。首先,我们需要理解什么是消息转发,以及它在Swift中的工作原理。 **一、消息转发机制** 在Objective-C中,当对象...