- 浏览: 447112 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (162)
- easymock (3)
- 模板引擎 (3)
- JForum (4)
- web (9)
- spring (10)
- java (20)
- struts (9)
- uml (3)
- java pattern (19)
- JQuery (14)
- 多线程 (13)
- database (21)
- PS (3)
- ejb (6)
- 版本管理 svn , maven , ant (2)
- protocol (1)
- 测试 (1)
- ws (7)
- Apache (4)
- 脚本语言 (1)
- guice (1)
- 分布式 (4)
- 架构 (0)
- 经验 (1)
- 版本管理 svn (1)
- maven (1)
- ant (1)
- 书籍 (1)
- Linux (1)
最新评论
-
Master-Gao:
稍微明白了点,,有点萌萌哒
为什么匿名内部类参数必须为final类型 -
waw0931:
终于明白了,谢谢!
为什么匿名内部类参数必须为final类型 -
十三圆桌骑士:
提供了两个链接还是有用的。
安装Mondrian -
放方芳:
[flash=200,200][/flash]
Freemarker标签使用 -
放方芳:
[b][/b]
Freemarker标签使用
1
.对象的强、软、弱和虚引用
在
JDK 1.2
以前的版本中,若一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及(
reachable
)状态,程序才能使用它。从
JDK 1.2
版本开始,把对象的引用分为
4
种级别,从而使程序能更加灵活地控制对象的生命周期。这
4
种级别由高到低依次为:强引用、软引用、弱引用和虚引用。图
1
为对象应用类层次。
图1
⑴
强引用(
StrongReference
)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,
Java
虚拟机宁愿抛出
OutOfMemoryError
错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
⑵软引用(
SoftReference
)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(
ReferenceQueue
)联合使用,如果软引用所引用的对象被垃圾回收器回收,
Java
虚拟机就会把这个软引用加入到与之关联的引用队列中。
⑶弱引用(
WeakReference
)
弱
引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不
管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(
ReferenceQueue
)联合使用,如果弱引用所引用的对象被垃圾回收,
Java
虚拟机就会把这个弱引用加入到与之关联的引用队列中。
⑷虚引用(
PhantomReference
)
“
虚引用
”
顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列
(
ReferenceQueue
)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之
关联的引用队列中。
ReferenceQueue
queue
=
new
ReferenceQueue ();
PhantomReference
pr
=
new
PhantomReference (
object
,
queue
);
|
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
2
.对象可及性的判断
在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。如图
2
所示
在这个树形的引用链中,箭头的方向代表了引用的方向,所指向的对象是被引用对象。由图可以看出,从根集到一个对象可以由很多条路径。比如到达对象
5
的路径就有①
-
⑤,③
-
⑦两条路径。由此带来了一个问题,那就是某个对象的可及性如何判断
:
◆单条引用路径可及性判断
:
在这条路径中,最弱的一个引用决定对象的可及性。
◆多条引用路径可及性判断
:
几条路径中,最强的一条的引用决定对象的可及性。
比如,我们假设图
2
中引用①和③为强引用,⑤为软引用,⑦为弱引用,对于对象
5
按照这两个判断原则,路径①
-
⑤取最弱的引用⑤,因此该路径对对象
5
的引用为软引用。同样,③
-
⑦为弱引用。在这两条路径之间取最强的引用,于是对象
5
是一个软可及对象。
3
.使用软引用构建敏感数据的缓存
3.1
为什么需要使用软引用
首先,我们看一个雇员信息查询系统的实例。我们将使用一个
Java
语言实现的雇员信息查询系统查询存储在磁盘文件或者数据库中的雇员人事档案信息。作为一个用户,我们完全有可能需要回头去查看几分钟甚至几秒钟前查看过的雇员档案信息
(
同样,我们在浏览
WEB
页面的时候也经常会使用“后退”按钮
)
。这时我们通常会有两种程序实现方式
:
一种是把过去查看过的雇员信息保存在内存中,每一个存储了雇员档案信息的
Java
对象的生命周期贯穿整个应用程序始终
;
另一种是当用户开始查看其他雇员的档案信息的时候,把存储了当前所查看的雇员档案信息的
Java
对
象结束引用,使得垃圾收集线程可以回收其所占用的内存空间,当用户再次需要浏览该雇员的档案信息的时候,重新构建该雇员的信息。很显然,第一种实现方法将
造成大量的内存浪费,而第二种实现的缺陷在于即使垃圾收集线程还没有进行垃圾收集,包含雇员档案信息的对象仍然完好地保存在内存中,应用程序也要重新构建
一个对象。我们知道,访问磁盘文件、访问网络资源、查询数据库等操作都是影响应用程序执行性能的重要因素,如果能重新获取那些尚未被回收的
Java
对象的引用,必将减少不必要的访问,大大提高程序的运行速度。
3.2
如果使用软引用
SoftReference
的特点是它的一个实例保存对一个
Java
对象的软引用,该软引用的存在不妨碍垃圾收集线程对该
Java
对象的回收。也就是说,一旦
SoftReference
保存了对一个
Java
对象的软引用后,在垃圾线程对这个
Java
对象回收前,
SoftReference
类所提供的
get()
方法返回
Java
对象的强引用。另外,一旦垃圾线程回收该
Java
对象之后,
get()
方法将返回
null
。
看下面代码
:
MyObject
aRef
=
new
MyObject();
SoftReference
aSoftRef
=
new
SoftReference(
aRef
);
|
此时,对于这个
MyObject
对象,有两个引用路径,一个是来自
SoftReference
对象的软引用,一个来自变量
aReference
的强引用,所以这个
MyObject
对象是强可及对象。
随即,我们可以结束
aReference
对这个
MyObject
实例的强引用
:
aRef
=
null
;
|
此后,这个
MyObject
对象成为了软可及对象。如果垃圾收集线程进行内存垃圾收集,并不会因为有一个
SoftReference
对该对象的引用而始终保留该对象。
Java
虚拟机的垃圾收集线程对软可及对象和其他一般
Java
对象进行了区别对待
:
软可及对象的清理是由垃圾收集线程根据其特定算法按照内存需求决定的。也就是说,垃圾收集线程会在虚拟机抛出
OutOfMemoryError
之前回收软可及对象,而且虚拟机会尽可能优先回收长时间闲置不用的软可及对象,对那些刚刚构建的或刚刚使用过的“新”软可反对象会被虚拟机尽可能保留。在回收这些对象之前,我们可以通过
:
MyObject
anotherRef
=(MyObject)
aSoftRef
.get();
|
重新获得对该实例的强引用。而回收之后,调用
get()
方法就只能得到
null
了。
3.3
使用
ReferenceQueue
清除失去了软引用对象的
SoftReference
作为一个
Java
对象,
SoftReference
对象除了具有保存软引用的特殊性之外,也具有
Java
对象的一般性。所以,当软可及对象被回收之后,虽然这个
SoftReference
对象的
get()
方法返回
null,
但这个
SoftReference
对象已经不再具有存在的价值,需要一个适当的清除机制,避免大量
SoftReference
对象带来的内存泄漏。在
java.lang.ref
包里还提供了
ReferenceQueue
。如果在创建
SoftReference
对象的时候,使用了一个
ReferenceQueue
对象作为参数提供给
SoftReference
的构造方法,如
:
ReferenceQueue
queue
=
new
ReferenceQueue();
SoftReference
ref
=
new
SoftReference(
aMyObject
,
queue
);
|
那么当这个
SoftReference
所软引用的
aMyOhject
被垃圾收集器回收的同时,
ref
所强引用的
SoftReference
对象被列入
ReferenceQueue
。也就是说,
ReferenceQueue
中保存的对象是
Reference
对象,而且是已经失去了它所软引用的对象的
Reference
对象。另外从
ReferenceQueue
这个名字也可以看出,它是一个队列,当我们调用它的
poll()
方法的时候,如果这个队列中不是空队列,那么将返回队列前面的那个
Reference
对象。
在任何时候,我们都可以调用
ReferenceQueue
的
poll()
方法来检查是否有它所关心的非强可及对象被回收。如果队列为空,将返回一个
null,
否则该方法返回队列中前面的一个
Reference
对象。利用这个方法,我们可以检查哪个
SoftReference
所软引用的对象已经被回收。于是我们可以把这些失去所软引用的对象的
SoftReference
对象清除掉。常用的方式为
:
SoftReference ref =
null
;
while
((ref = (EmployeeRef)
q
.poll()) !=
null
) {
//
清除
ref
}
|
理解了
ReferenceQueue
的工作机制之后,我们就可以开始构造一个
Java
对象的高速缓存器了。
3.4
通过软可及对象重获方法实现
Java
对象的高速缓存
利用
Java2
平台垃圾收集机制的特性以及前述的垃圾对象重获方法,我们通过一个雇员信息查询系统的小例子来说明如何构建一种高速缓存器来避免重复构建同一个对象带来的性能损失。我们将一个雇员的档案信息定义为一个
Employee
类
:
public
class
Employee {
private
String
id
;
//
雇员的标识号码
private
String
name
;
//
雇员姓名
private
String
department
;
//
该雇员所在部门
private
String
Phone
;
//
该雇员联系电话
private
int
salary
;
//
该雇员薪资
private
String
origin
;
//
该雇员信息的来源
//
构造方法
public
Employee(String id) {
this
.
id
= id;
getDataFromlnfoCenter();
}
//
到数据库中取得雇员信息
private
void
getDataFromlnfoCenter() {
//
和数据库建立连接井查询该雇员的信息,将查询结果赋值
//
给
name
,
department
,
plone
,
salary
等变量
//
同时将
origin
赋值为
"From DataBase"
}
……
|
这个
Employee
类的构造方法中我们可以预见,如果每次需要查询一个雇员的信息。哪怕是几秒中之前刚刚查询过的,都要重新构建一个实例,这是需要消耗很多时间的。下面是一个对
Employee
对象进行缓存的缓存器的定义
:
import
java.lang.ref.ReferenceQueue;
import
java.lang.ref.SoftReference;
import
java.util.Hashtable;
public
class
EmployeeCache {
static
private
EmployeeCache
cache
;
//
一个
Cache
实例
private
Hashtable<String,EmployeeRef>
employeeRefs
;
//
用于
Chche
内容的存储
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
);
}
}
发表评论
-
swingworker
2015-07-15 14:18 0Swing应用程序员常见的错误是误用Swin ... -
理解Java对象序列化(转)
2014-05-14 22:29 0理解Java对象序列化 关于Java序列化的文章早已是汗牛 ... -
web项目中Log4j不输出到文件问题
2013-03-06 17:50 17827log4j.propert ... -
java 补码解释
2012-07-07 10:46 8711.byte的大小为8bits而int的大小为32bit ... -
jms基础概念和应用场景(转)
2012-06-13 13:34 1151原文地址:http://blog.csdn.net/KimmK ... -
java GC和运行参数
2012-05-07 21:27 0java GC和运行参数 引言有JAVA开 ... -
java类加载顺序
2012-04-26 18:58 1425当程序中调用 new 指令,或 ... -
callable和future
2012-04-26 18:29 1083import java.util.concurren ... -
为什么匿名内部类参数必须为final类型
2012-04-26 18:26 286611) 从程序设计语言的理论上:局部内部类(即:定义在方法中的 ... -
JAVA 使用final参数的原因
2012-04-06 14:59 2346先介绍一些基本概念。 ... -
java内存
2012-03-05 15:12 0堆大小设置 JVM 中最大堆大小有三方 ... -
Java泛型详解
2011-11-23 17:49 953优点概述:是对 Java 语言的类型系统的一种扩展,规定集合中 ... -
java 堆和栈
2011-11-08 17:44 811简单概括一下: java栈 存放 基本类型的字面 ... -
jvm全局理解
2011-09-11 15:54 10851 Java技术与Java虚拟机 说起Java,人们 ... -
hashmap死循环
2011-08-25 22:29 2343本文受http://pt.alibaba-inc. ... -
hashmap
2011-08-24 21:29 1151在Java中任何一个对象都具备equals(Object ... -
properties 占位符
2011-05-16 15:09 2201MessageFormat - java.text.M ... -
EditPlus正则表达式替换字符串详解
2010-10-12 15:51 1272正则表达式是一个查询 ... -
HashMap 源码解读
2010-08-05 16:56 1416HashMap是我们在日常写代码时最常用到的一个数据结构,它为 ... -
array.sort源码解释
2010-07-13 13:58 1466* fast: it is guaranteed to run ...
相关推荐
从JDK 1.2版本开始,Java引入了四种不同级别的引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)。这些引用类型提供了灵活的内存管理策略,允许...
强引用、弱引用、软引用和虚引用是四种不同的引用强度,它们在垃圾回收机制中扮演着不同的角色。了解这些引用类型对于优化内存使用、防止内存泄漏以及合理地控制对象生命周期至关重要。 1. **强引用(Strong ...
为了更好地理解和控制对象的生命周期,Java提供了四种不同类型的引用:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)以及虚引用(Phantom Reference)。每种引用都有其特定的...
从Java SE2开始,Java引入了四种不同类型的引用:强引用、软引用、弱引用和虚引用,它们各自具有不同的特点和用途,有助于程序员更精细地控制对象的生命周期,并优化垃圾回收过程。 1. 强引用(Strong Reference) ...
然而,为了更好地控制内存,Java提供了不同类型的引用:强引用、弱引用、软引用和虚引用。这些引用类型允许程序员在特定场景下干预垃圾收集过程,以达到更精细的内存管理。 1. **强引用(Strong Reference)** - *...
### Java中的软引用、弱引用和虚引用详解 #### 一、引言 在Java开发过程中,特别是Android应用开发中,经常会遇到一个普遍的问题——内存溢出(OutOfMemory Error,简称OOM)。这个问题往往与如何有效地管理内存...
Java对象的引用类型是Java内存管理中的重要概念,特别是在JDK 1.2及后续版本中引入了四种级别的引用:强引用、软引用、弱引用和虚引用,以提供更精细的控制对象生命周期的能力。 1. **强引用(StrongReference)**: ...
这个"referenceInJava"项目专注于探讨四种不同类型的引用:强引用、软引用、弱引用和虚引用。这些引用类型与垃圾收集(Garbage Collection, GC)机制密切相关,对于优化内存使用和防止内存泄漏至关重要。 1. **强...
Java 中强引用、软引用、弱引用概念解析 Java 中强引用、软引用、弱引用是 Java 语言...Java 中的强引用、软引用、弱引用和虚引用四种引用类型都有其特点和应用场景,选择合适的引用类型可以提高程序的性能和可读性。
在 Java 中,引用可以分为四类:强引用、软引用、弱引用和虚引用(也称为精灵引用)。弱引用是其中的一种,它们允许垃圾回收器在某些情况下回收对象,而不是像强引用那样坚持对象的存在。 弱引用的工作原理是,当...
强引用、弱引用、软引用和虚引用这四种引用类型提供了不同的对象生命周期管理策略。下面将详细介绍这些引用的区别及其应用场景。 1. **强引用(Strong Reference)** - 强引用是最常见的引用类型,如普通变量引用。...
在Java中,为了更好地管理对象的生命周期,从JDK 1.2开始引入了四种不同级别的引用类型:强引用、软引用、弱引用和虚引用。每种引用类型都有其特定的应用场景,通过灵活运用这些引用类型,开发者可以在内存管理和...
在JDK1.2以前的版本中,当一个对象不被任何变量引用,那么程序就无法再使用这个对象。也就是说,只有对象处于可触及状态,程序才能使用它。这 就像在日常生活中,从商店购买了某样物品后,如果有用,就一直保留它,...
本文将深入探讨四种引用类型:强引用、软引用、弱引用和虚引用。 首先,我们来理解强引用(Strong Reference)。强引用是最常见的引用类型,它代表了程序中的普通对象引用。当一个对象被强引用指向时,该对象被认为...
如果一个对象没有强引用和软引用,对于垃圾回收器而言便是可以被清除的,在清除之前,会调用其finalize方法,如果一个对象已经被调用过finalize方法但是还没有被释放,它就变成了一个虚可达对象。 与软引用和弱引用...
本文将深入探讨强引用、软引用、弱引用以及幻象引用这四种引用类型,以及它们与垃圾收集的关系。 1. **强引用(Strong Reference)**: - 强引用是Java中最常见的引用类型,它代表了一个对象的直接访问路径。只要...
从JDK 1.2版本开始,Java引入了一种更为精细的引用类型管理机制,通过四种不同的引用类型:强引用、软引用、弱引用和虚引用,让开发者能够更加灵活地控制对象的生命周期。这种机制不仅提升了Java应用程序对内存使用...
由于弱引用不会阻止垃圾收集,所以使用弱引用的对象在被创建后会很快变得不可达,除非有其他强引用指向它。这在一定程度上保证了内存的有效利用,避免了不必要的内存占用。 在Android中,软引用和弱引用常用于图片...
JAVA 强引用详解 JAVA 强引用是JAVA 中最基本的引用类型,也是我们在编程中最常用的引用方式。强引用是使用最普遍的引用类型,如果一个对象具有强引用,那么垃圾回收器宁愿抛出OOM(OutOfMemoryError)也不会回收它...
Java中的四种引用类型是Java内存管理的重要组成部分,它们分别是强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference)。每种引用类型具有不同的特点和用途,...