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

2016-02-19 18:56 0 1 收藏

今天图老师小编给大家精心推荐个Java理论和实践:用软引用阻止内存泄漏教程,一起来看看过程究竟如何进行吧!喜欢还请点个赞哦~

【 tulaoshi.com - 编程语言 】

   在本文中,他将解释 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 SoftReferencebufferRef;
  
   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
   }
  }

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)


来源:https://www.tulaoshi.com/n/20160219/1619581.html

延伸阅读
标签: Web开发
     最近做一个公司的业务系统,公司要求能尽可能的与c/s近似,也就是如c/s一样,点击文本框可以弹出此项目的相关内容,进行选择输入。      我使用了弹出窗口,然后在子窗口双击选中项目,把选中的值返回给父窗体。      在系统做完了之后,在客户使用的过程,由于客户使用的是...
标签: Web开发
浏览本站的 Javascript教程 栏目内容。 常规循环引用内存泄漏和Closure内存泄漏 要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理。 我记得原来在犀牛书《JavaScript: The Definitive Guide》中看到过,IE使用的GC算法是计数器,因此只碰到循环 引用就会造成memory leakage。后来一直觉得和观察到的现象很不一...
标签: Web开发
原文地址:http://www.jackslocum.com/blog/2006/10/02/3-easy-steps-to-avoid-javascript-memory-leaks/你可能还未知道,你浏览的大多数的js网站,会引起 内存泄漏。听起来有点夸张,但这是事实,难道我会骗你吗? 泄漏监视器Leak Monitor 这是个方便的FireFox扩展,当你离开那页的时候它便会指向JavsScript对象,如果出现泄漏的话会弹出一...
Java 提供两种不同的类型:引用类型和原始类型(或内置类型)。另外,Java 还为每个原始类型提供了封装类(Wrapper)。如果需要一个整型变量,是使用基本的 int 型呢,还是使用 Integer 类的一个对象呢?如果需要声明一个布尔类型,是使用基本的 boolean,还是使用 Boolean 类的一个对象呢?本文可帮助您作出决定。 下表列出了原始类型以及它们...
 Java开源实践1--环境配置  wuder Window系统下的deploy所需软件: 以下软件为window下执行 Jdk5.0 下载地址:http://java.sun.com/j2se/1.5.0/download.jsp           jdk-1_5_0_01-windows-i586-p.exe Jboss4.01 ...

经验教程

728

收藏

80
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部