首页 | 资讯动态 | linux基础 | 系统管理 | 网络管理 | 编程开发 | linux数据库 | 服务器技术 | linux相关 | linux认证 | 嵌入式 | 下载中心 | 专题 | linux招聘 | 镜像站
OKLinux中文技术站
·设为首页
·加入收藏
·联系我们
系统管理: 中文环境 系统管理 桌面应用 内核技术 | Linux基础: 基础入门 安装配置 常用命令 经验技巧 软件应用 | Linux数据库: Mysql Postgre Oracle DB2 Sybase other
网络管理: 网络安全 网络应用 Linux服务器 环境配置 黑客安全 | 编程开发: PHP CC++ Python Perl Shell 嵌入式开发 java jsp | PHP技术: PHP基础 PHP技巧 PHP应用 PHP文摘
Linux资讯 Linux招聘 Linux专题 Apache | Linux相关: 硬件相关 Linux解决方案 Linux认证 企业应用 其它Unix | 相关下载: 资料下载 参考手册 开发工具 服务器类 软路由 其它
 技术搜索:
会员中心 注册会员 高级搜索  
  → 当前位置:首页>编程开发>java>Java基础>正文

Java 理论和实践:用软引用阻止内存泄漏

http://www.oklinux.cn  2008-01-25  来源: 赛迪网 leonade  会员收藏  游客收藏  【 】 

在 Java 理论和实践 的 前一期文章 中,Java™ 清洁工程师 Brian Goetz 探究了弱引用(weak references),它让您警告垃圾收集器,您想要维护一个对象的引用,而不会阻止该对象被垃圾收集。在本期文章中,他将解释 Reference 对象的另外一种形式,即软引用(soft references),用于帮助垃圾收集器治理内存使用和消除潜在的内存泄漏。
垃圾收集可以使 Java 程序不会出现内存泄漏,至少对于比较狭窄的 “内存泄漏” 定义来说如此,但是这并不意味着我们可以完全忽略 Java 程序中的对象生存期(lifetime)问题。当我们没有对对象生命周期(lifecycle)引起足够的重视或者破坏了治理对象生命周期的标准机制时,Java 程序中通常就会出现内存泄漏。例如,上一次 我们看到了,不能划分对象的生命周期会导致,在试图将元数据关联到瞬时对象时出现意外的对象保持。还有一些其他的情况可以类似地忽略或破坏对象生命周期治理,并导致内存泄漏。

对象游离

一种形式的内存泄漏有时候叫做对象游离(object loitering),是通过清单 1 中的 LeakyChecksum 类来说明的,清单 1 中有一个 getFileChecksum() 方法用于计算文件内容的校验和。getFileChecksum() 方法将文件内容读取到缓冲区中以计算校验和。一种更加直观的实现简单地将缓冲区作为 getFileChecksum() 中的本地变量分配,但是该版本比那样的版本更加 “聪明”,不是将缓冲区缓存在实例字段中以减少内存 churn。该 “优化”通常不带来预期的好处;对象分配比很多人期望的更便宜。(还要注重,将缓冲区从本地变量提升到实例变量,使得类若不带有附加的同步,就不再是线程安全的了。直观的实现不需要将 getFileChecksum() 声明为 synchronized,并且会在同时调用时提供更好的可伸缩性。)


清单 1. 展示 “对象游离” 的类

// BAD CODE - DO NOT EMULATE
public class LeakyChecksum {
private byte[] byteArray;

public synchronized int getFileChecksum(String fileName) {
int len = getFileSize(fileName);
if (byteArray == null || byteArray.length < len)
byteArray = new byte[len];
readFileContents(fileName, byteArray);
// calculate checksum and return it
}
}



这个类存在很多的问题,但是我们着重来看内存泄漏。缓存缓冲区的决定很可能是根据这样的假设得出的,即该类将在一个程序中被调用许多次,因此它应该更加有效,以重用缓冲区而不是重新分配它。但是结果是,缓冲区永远不会被释放,因为它对程序来说总是可及的(除非 LeakyChecksum 对象被垃圾收集了)。更坏的是,它可以增长,却不可以缩小,所以 LeakyChecksum 将永久保持一个与所处理的最大文件一样大小的缓冲区。退一万步说,这也会给垃圾收集器带来压力,并且要求更频繁的收集;为计算未来的校验和而保持一个大型缓冲区并不是可用内存的最有效利用。

LeakyChecksum 中问题的原因是,缓冲区对于 getFileChecksum() 操作来说逻辑上是本地的,但是它的生命周期已经被人为延长了,因为将它提升到了实例字段。因此,该类必须自己治理缓冲区的生命周期＀?而不是让 JVM 来治理。


软引用

在 前一期文章 中我们看到了,弱引用如何可以给应用程序提供当对象被程序使用时另一种到达该对象的方法,但是不会延长对象的生命周期。Reference 的另一个子类 ?? 软引用 ?? 可满足一个不同却相关的目的。其中弱引用答应应用程序创建不妨碍垃圾收集的引用,软引用答应应用程序通过将一些对象指定为 “expendable” 而利用垃圾收集器的帮助。尽管垃圾收集器在找出哪些内存在由应用程序使用哪些没在使用方面做得很好,但是确定可用内存的最适当使用还是取决于应用程序。假如应用程序做出了不好的决定,使得对象被保持,那么性能会受到影响,因为垃圾收集器必须更加辛勤地工作,以防止应用程序消耗掉所有内存。

高速缓存是一种常见的性能优化,答应应用程序重用以前的计算结果,而不是重新进行计算。高速缓存是 CPU 利用和内存使用之间的一种折衷,这种折衷理想的平衡状态取决于有多少内存可用。若高速缓存太少,则所要求的性能优势无法达到;若太多,则性能会受到影响,因为太多的内存被用于高速缓存上,导致其他用途没有足够的可用内存。因为垃圾收集器比应用程序更适合决定内存需求,所以应该利用垃圾收集器在做这些决定方面的帮助,这就是件引用所要做的。

假如一个对象惟一剩下的引用是弱引用或软引用,那么该对象是软可及的(softly reachable)。垃圾收集器并不像其收集弱可及的对象一样尽量地收集软可及的对象,相反,它只在真正 “需要” 内存时才收集软可及的对象。软引用对于垃圾收集器来说是这样一种方式,即 “只要内存不太紧张,我就会保留该对象。但是假如内存变得真正紧张了,我就会去收集并处理这个对象。” 垃圾收集器在可以抛出 OutOfMemoryError 之前需要清除所有的软引用。

通过使用一个软引用来治理高速缓存的缓冲区,可以解决 LeakyChecksum 中的问题,如清单 2 所示。现在,只要不是非凡需要内存,缓冲区就会被保留,但是在需要时,也可被垃圾收集器回收:


清单 2. 用软引用修复 LeakyChecksum

public class CachingChecksum {
private SoftReference bufferRef;

public synchronized int getFileChecksum(String fileName) {
int len = getFileSize(fileName);
byte[] byteArray = bufferRef.get();
if (byteArray == null || byteArray.length < len) {
byteArray = new byte[len];
bufferRef.set(byteArray);
}
readFileContents(fileName, byteArray);
// calculate checksum and return it
}
}



一种廉价的缓存

CachingChecksum 使用一个软引用来缓存单个对象,并让 JVM 处理从缓存中取走对象时的细节。类似地,软引用也经常用于 GUI 应用程序中,用于缓存位图图形。是否可使用软引用的要害在于,应用程序是否可从大量缓存的数据恢复。

共2页: 上一页 1 [2] 下一页

上一篇:详细分析Linux系统计算机死机的故障原因   下一篇:系统管理:修复Linux系统的Root密码


收藏于收藏夹】 【评论】 【推荐】 【打印】 【关闭
相关文档
·初始化引发的"StackOverflowError" 异常
·接口与抽象类的深层理解
·Java语言深入--java调用C/C 的过程
·J2SE综合--怎样取得class文件的路径
·JSP/Servlet:EasyJWeb中文件上传的处理
·Java入门:java语言中创建和使用日期
·Java怎样调用外部应用程序
·关于角色访问控制(RBAC)
·J2SE综合--为什么Java中继承是有害的
·Java语言中Timer类的简洁用法
·进阶-Java Web中的入侵检测及简单实现
·Java入门:java中不同类型的转换和提升
·基础--websphere下JMS的配置和和应用
·为什么很多Java开发人员对JCP感觉失望
·JAVA学习入门 对初次接触者 相当的有用
·JSP/Servlet:< jsp-config>标签使用详解
发表评论
密码: 匿名评论
评论内容:

(不超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规)
 
  最新文档
·Java入门:状态对象--数据库的替代者
·Java语言怎样调用外部应用程序
·Java语言深入--关于Java语言的内存泄漏
·JSP/Servlet/JSF:Servlet/JSP配置详解
·进阶-怎样使用AJAX进行WEB应用程序开发
·基础:J2ME程序开发之新手入门九大要点
·Java入门--Java语言接口与继承的本质
·JAVA进阶--如何提升JSP应用程序的效率
·对Java中四种XML解析技术之不完全测试
·编写高级 JScript应用代码
·JSP/Servlet/JSF--对标签库的深入研究
·Java入门--关于字符串分割的两种方法
  阅读排行
·使用AJAX技术实现网页无闪自动局部刷新
·快速教您Apache Tomcat SSL的配置
·Java语言深入--java调用C/C 的过程
·用JSP JavaScript打造二级级联下拉菜单
·JAVA进阶--线程运行栈信息的获取讲解
·使用WEBWORK实现文件上传方法实例详解
·J2SE综合--JAVA实现把汉字转化成拼音
·一个非常有趣的使用spring框架AOP例子
·关于java中相对路径,绝对路径问题总结
·高级:lucene全文检索应用示例及代码简
·详细讲解Struts构架中action的跳转大全
·在Weblogic上配置JMS服务的方法
·Hibernate配置文件中的映射元素详解
·对Java中四种XML解析技术之不完全测试
·在JSP环境中配置使用fckeditor详细讲解
网摘收藏: