如何在您的Java应用中linux 查找应用并修复内存泄漏

如何防止java中的内存泄漏_百度知道
如何防止java中的内存泄漏
我有更好的答案
1、Java中有自回收垃圾机制GC2、有些连接比如数据库、IO流等要进行手动.close()方法进行关闭,达到内存操作其中:垃圾回收机制GC其实就是设置一个根节点,然后在这个程序中,判断变量或者对象是否还属于这个根节点,如果不属于了,则判断为垃圾需要回收,否则就继续保存
java开发工程师
  尽管java虚拟机和垃圾回收机制治理着大部分的内存事务,但是在java软件中还是可能存在内存泄漏的情况。的确,在大型工程中,内存泄漏是一个普遍问题。避免内存泄漏的第一步,就是要了解他们发生的原因。这篇文章就是要介绍一些常见的缺陷,然后提供一些非常好的实践例子来指导你写出没有内存泄漏的代码。一旦你的程序存在内存泄漏,要查明代码中引起泄漏的原因是很困难的。同时这篇文章也要介绍一个新的工具来查找内存泄漏,然后指明发生的根本原因。这个工具轻易上手,可以让你找到产品级系统中的内存泄漏。    垃圾回收(GC)的角色    虽然垃圾回收关心着大部分的问题,包括内存治理,使得程序员的任务显得更加轻松,但是程序员还是可能犯些错误导致内存泄漏问题。GC(垃圾回收)通过递归对所有从“根”对象(堆栈中的对象,静态数据成员,JNI句柄等等)继续下来的引用进行工作,然后标记所有可以访问的活动着的对象。而这些对象变成了程序唯一能够操纵的对象,其他的对象都被释放了。因为GC使得程序不能够访问那些被释放的对象,所以这样做是安全的。    内存治理可以说是自动的,但是这并没有让程序员脱离内存治理问题。比方说,对于内存的分配(还有释放)总是存在一定的开销,尽管这些开销对程序员来说是隐含的。一个程序假如创建了很多对象,那么它就要比完成相同任务而创建了较少对象的程序执行的速度慢(假如其他的条件都相同)。    文章更多想说的,导致内存泄漏主要的原因是,先前申请了内存空间而忘记了释放。假如程序中存在对无用对象的引用,那么这些对象就会驻留内存,消耗内存,因为无法让垃圾回收器验证这些对象是否不再需要。正如我们前面看到的,假如存在对象的引用,这个对象就被定义为“活动的”,同时不会被释放。要确定对象所占内存将被回收,程序员就要务必确认该对象不再会被使用。典型的做法就是把对象数据成员设为null或者从集合中移除该对象。注重,当局部变量不需要时,不需明显的设为null,因为一个方法执行完毕时,这些引用会自动被清理。    从更高一个层次看,这就是所有存在内存管的语言对内存泄漏所考虑的事情,剩余的对象引用将不再会被使用。    典型的泄漏    既然我们知道了在java中确实会存在内存泄漏,那么就让我们看一些典型的泄漏,并找出他们发生的原因。    全局集合    在大型应用程序中存在各种各样的全局数据仓库是很普遍的,比如一个JNDI-tree或者一个session table。在这些情况下,注重力就被放在了治理数据仓库的大小上。当然是有一些适当的机制可以将仓库中的无用数据移除。    可以有很多不同的解决形式,其中最常用的是一种周期运行的清除作业。这个作业会验证仓库中的数据然后清除一切不需要的数据。    另一个办法是计算引用的数量。集合负责跟踪集合中每个元素的引用者数量。这要求引用者通知集合什么时候已经对元素处理完毕。当引用者的数目为零时,就可以移除集合中的相关元素。    高速缓存    高速缓存是一种用来快速查找已经执行过的操作结果的数据结构。因此,假如一个操作执行很慢的话,你可以先把普通输入的数据放入高速缓存,然后过些时间再调用高速缓存中的数据。    高速缓存多少还有一点动态实现的意思,当数据操作完毕,又被送入高速缓存。一个典型的算法如下所示:    1. 检查结果是否在高速缓存中,存在则返回结果;    2. 假如结果不在,那么计算结果;    3. 将结果放入高速缓存,以备将来的操作调用。    这个算法的问题(或者说潜在的内存泄漏)在最后一步。假如操作是分别多次输入,那么存入高速缓存的内容将会非常大。很明显这个方法不可取。    为了避免这种潜在的致命错误设计,程序就必须确定高速缓存在他所使用的内存中有一个上界。因此,更好的算法是:    1. 检查结果是否在高速缓存中,存在则返回结果;    2. 假如结果不在,那么计算结果;    3. 假如高速缓存所占空间过大,移除缓存中旧的结果;    4. 将结果放入高速缓存,以备将来的操作调用。    通过不断的从缓存中移除旧的结果,我们可以假设,将来,最新输入的数据可能被重用的几率要远远大于旧的结果。这通常是一个不错的设想。    这个新的算法会确保高速缓存的容量在预先确定的范围内。精确的范围是很难计算的,因为缓存中的对象存在引用时将继续有效。正确的划分高速缓存的大小是一个复杂的任务,你必须权衡可使用内存大小和数据快速存取之间的矛盾。    另一个解决这个问题的途径是使用java.lang.ref.SoftReference类来将对象放入高速缓存。这个方法可以保证当虚拟机用完内存或者需要更多堆的时候,可以释放这些对象的引用。    类装载器    Java类装载器创建就存在很多导致内存泄漏的漏洞。由于类装载器的复杂结构,使得很难得到内存泄漏的透视图。这些困难不仅仅是由于类装载器只与“普通的”对象引用有关,同时也和对象内部的引用有关,比如数据变量,方法和各种类。这意味着只要存在对数据变量,方法,各种类和对象的类装载器,那么类装载器将驻留在JVM中。既然类装载器可以同很多的类关联,同时也可以和静态数据变量关联,那么相当多的内存就可能发生泄漏。    定位内存泄漏    经常地,程序内存泄漏的最初迹象发生在出错之后,在你的程序中得到一个OutOfMemoryError。这种典型的情况发生在产品环境中,而在那里,你希望内存泄漏尽可能的少,调试的可能性也达到最小。也许你的测试环境和产品的系统环境不尽相同,导致泄露的只会在产品中暴露。这种情况下,你需要一个低负荷的工具来监听和寻找内存泄漏。同时,你还需要把这个工具同你的系统联系起来,而不需要重新启动他或者机械化你的代码。也许更重要的是,当你做分析的时候,你需要能够同工具分离而使得系统不会受到干扰。    一个OutOfMemoryError经常是内存泄漏的一个标志,有可能应用程序的确用了太多的内存;这个时候,你既不能增加JVM的堆的数量,也不能改变你的程序而使得他减少内存使用。但是,在大多数情况下,一个OutOfMemoryError是内存泄漏的标志。一个解决办法就是继续监听GC的活动,看看随时间的流逝,内存使用量是否会增加,假如有,程序中一定存在内存泄漏。    具体输出    有很多办法来监听垃圾回收器的活动。也许运用最广泛的就是以:-Xverbose:gc选项运行JVM,然后观察输出结果一段时间。    [memory] 10.109-10.235: GC 65536K-&16788K (65536K), 126.000 ms    箭头后的值(在这个例子中 16788K)是垃圾回收后堆的使用量。    控制台    观察这些无尽的GC具体统计输出是一件非常单调乏味的事情。好在有一些工具来代替我们做这些事情。The JRockit Management Console可以用图形的方式输出堆的使用量。通过观察图像,我们可以很方便的观察堆的使用量是否伴随时间增长。     Figure 1. The JRockit Management Console    治理控制台甚至可以配置成在堆使用量出现问题(或者其他的事件发生)时向你发送邮件。这个显然使得监控内存泄漏更加轻易。    内存泄漏探测工具    有很多专门的内存泄漏探测工具。其中The JRockit Memory Leak Detector可以供来观察内存泄漏也可以针对性地找到泄漏的原因。这个强大的工具被紧密地集成在JRockit JVM中,可以提供最低可能的内存事务也可以轻松的访问虚拟机的堆。    专门工具的优势    一旦你知道程序中存在内存泄漏,你需要更专业的工具来查明为什么这里会有泄漏。而JVM是不可能告诉你的。现在有很多工具可以利用了。这些工具本质上主要通过两种方法来得到JVM的存储系统信息的:JVMTI和字节码仪器。Java虚拟机工具接口(JVMTI)和他的原有形式JVMPI(压型接口,PRofiling Interface)都是标准接口,作为外部工具同JVM进行通信,搜集JVM的信息。字节码仪器则是引用通过探针获得工具所需的字节信息的预处理技术。    通过这些技术来侦测内存泄漏存在两个缺点,而这使得他们在产品级环境中的运用不够理想。首先,根据两者对内存的使用量和内存事务性能的降级是不可以忽略的。从JVM获得的堆的使用量信息需要在工具中导出,收集和处理。这意味着要分配内存。按照JVM的性能导出信息是需要开销的,垃圾回收器在搜集信息的时候是运行的非常缓慢的。另一个缺点就是,这些工具所需要的信息是关系到JVM的。让工具在JVM开始运行的时候和它关联,而在分析的时候,分离工具而保持JVM运行,这显然是不可能的。    既然JRockit Memory Leak Detector是被集成到JVM中的,那么以上两种缺点就不再存在。首先,大部分的处理和分析都是在JVM中完成的,所以就不再需要传送或重建任何数据。处理也可以建立在垃圾回收器的基础上,即提高速度。再有,内存泄漏侦测器可以同一个运行的JVM关联和分离,只要JVM在开始的时候伴随着 –Xmanagement选项(通过远程JMX接口答应监听和治理JVM)。当工具分离以后,工具不会遗留任何东西在JVM中;JVM就可以全速运行代码就似乎工具关联之前一样。    
try{}catch捕捉内存溢出异常
为您推荐:
其他类似问题
内存泄漏的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。Linux下如何定位JAVA进程直接内存的泄漏及top和jmap查看内存的关系
[问题点数:100分,结帖人jiangguilong2000]
Linux下如何定位JAVA进程直接内存的泄漏及top和jmap查看内存的关系
[问题点数:100分,结帖人jiangguilong2000]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2012年8月 总版技术专家分月排行榜第三2012年7月 总版技术专家分月排行榜第三
2014年8月 高性能开发大版内专家分月排行榜第一2013年11月 高性能开发大版内专家分月排行榜第一2012年12月 Java大版内专家分月排行榜第一2012年11月 Java大版内专家分月排行榜第一2012年10月 Java大版内专家分月排行榜第一2012年9月 Java大版内专家分月排行榜第一2012年8月 Java大版内专家分月排行榜第一2012年7月 Java大版内专家分月排行榜第一2012年6月 Java大版内专家分月排行榜第一2012年5月 Java大版内专家分月排行榜第一2012年4月 Java大版内专家分月排行榜第一2012年3月 Java大版内专家分月排行榜第一2012年2月 Java大版内专家分月排行榜第一2012年1月 Java大版内专家分月排行榜第一
匿名用户不能发表回复!|推荐这篇日记的豆列
&&&&&&&&&&&&理解Java中的内存泄露及解决方法示例
转载 &更新时间:日 08:55:14 & 投稿:junjie
这篇文章主要介绍了理解Java中的内存泄露及解决方法示例,本文讲解了Java内存管理机制、Java内存泄露、一般情况下内存泄漏的避免、复杂数据结构中的内存泄露问题等内容,需要的朋友可以参考下
本文详细地介绍了Java内存管理的原理,以及内存泄露产生的原因,同时提供了一些列解决Java内存泄露的方案,希望对各位Java开发者有所帮助。
Java内存管理机制
在C++ 语言中,如果需要动态分配一块内存,程序员需要负责这块内存的整个生命周期。从申请分配、到使用、再到最后的释放。这样的过程非常灵活,但是却十分繁琐,程序员很容易由于疏忽而忘记释放内存,从而导致内存的泄露。 Java 语言对内存管理做了自己的优化,这就是垃圾回收机制。 Java 的几乎所有内存对象都是在堆内存上分配(基本数据类型除外),然后由 GC ( garbage collection)负责自动回收不再使用的内存。
上面是Java 内存管理机制的基本情况。但是如果仅仅理解到这里,我们在实际的项目开发中仍然会遇到内存泄漏的问题。也许有人表示怀疑,既然 Java 的垃圾回收机制能够自动的回收内存,怎么还会出现内存泄漏的情况呢?这个问题,我们需要知道 GC 在什么时候回收内存对象,什么样的内存对象会被 GC 认为是“不再使用”的。
Java中对内存对象的访问,使用的是引用的方式。在 Java 代码中我们维护一个内存对象的引用变量,通过这个引用变量的值,我们可以访问到对应的内存地址中的内存对象空间。在 Java 程序中,这个引用变量本身既可以存放堆内存中,又可以放在代码栈的内存中(与基本数据类型相同)。 GC 线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的。如果 GC 线程通过这种方式,无法跟踪到某一块堆内存,那么 GC 就认为这块内存将不再使用了(因为代码中已经无法访问这块内存了)。
通过这种有向图的内存管理方式,当一个内存对象失去了所有的引用之后,GC 就可以将其回收。反过来说,如果这个对象还存在引用,那么它将不会被 GC 回收,哪怕是 Java 虚拟机抛出 OutOfMemoryError 。
Java内存泄露
一般来说内存泄漏有两种情况。一种情况如在C/C++ 语言中的,在堆中的分配的内存,在没有将其释放掉的时候,就将所有能访问这块内存的方式都删掉(如指针重新赋值);另一种情况则是在内存对象明明已经不需要的时候,还仍然保留着这块内存和它的访问方式(引用)。第一种情况,在 Java 中已经由于垃圾回收机制的引入,得到了很好的解决。所以, Java 中的内存泄漏,主要指的是第二种情况。
可能光说概念太抽象了,大家可以看一下这样的例子:
Vector v = new& Vector( 10 );&
for& ( int& i = 1 ;i & 100 ; i ++ ){&
Object o = new& Object();&
v.add(o);&
在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是当 o 引用被置空后,如果发生 GC ,我们创建的 Object 对象是否能够被 GC 回收呢?答案是否定的。因为, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管 o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。
尽管对于C/C++ 中的内存泄露情况来说, Java 内存泄露导致的破坏性小,除了少数情况会出现程序崩溃的情况外,大多数情况下程序仍然能正常运行。但是,在移动设备对于内存和 CPU都有较严格的限制的情况下, Java 的内存溢出会导致程序效率低下、占用大量不需要的内存等问题。这将导致整个机器性能变差,严重的也会引起抛出 OutOfMemoryError ,导致程序崩溃。
一般情况下内存泄漏的避免
在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度。我们有时也将其称为“对象游离”。
public class FileSearch{&
&&&&& private byte []&
&&&&& private File mF&
&&&& public FileSearch(File file){&
&&&&& mFile =&
&&&& public boolean hasString(String str){&
&&&&&&&& int size = getFileSize(mFile);&
&&&&&&& content =& new& byte [size];&
&&&&&&&& loadFile(mFile, content);&
&&&&&&&& String s =& new String(content);&
&&&&&&&& return s.contains(str);&
在这段代码中,FileSearch 类中有一个函数 hasString ,用来判断文档中是否含有指定的字符串。流程是先将mFile 加载到内存中,然后进行判断。但是,这里的问题是,将 content 声明为了实例变量,而不是本地变量。于是,在此函数返回之后,内存中仍然存在整个文件的数据。而很明显,这些数据我们后续是不再需要的,这就造成了内存的无故浪费。
要避免这种情况下的内存泄露,要求我们以C/C++ 的内存管理思维来管理自己分配的内存。第一,是在声明对象引用之前,明确内存对象的有效作用域。在一个函数内有效的内存对象,应该声明为 local 变量,与类实例生命周期相同的要声明为实例变量……以此类推。第二,在内存对象不再需要时,记得手动将其引用置空。
复杂数据结构中的内存泄露问题
在实际的项目中,我们经常用到一些较为复杂的数据结构用于缓存程序运行过程中需要的数据信息。有时,由于数据结构过于复杂,或者我们存在一些特殊的需求(例如,在内存允许的情况下,尽可能多的缓存信息来提高程序的运行速度等情况),我们很难对数据结构中数据的生命周期作出明确的界定。这个时候,我们可以使用Java 中一种特殊的机制来达到防止内存泄露的目的。
之前我们介绍过,Java 的 GC 机制是建立在跟踪内存的引用机制上的。而在此之前,我们所使用的引用都只是定义一个“ O ”这样形式的。事实上,这只是 Java 引用机制中的一种默认情况,除此之外,还有其他的一些引用方式。通过使用这些特殊的引用机制,配合 GC 机制,就可以达到一些我们需要的效果。
Java中的几种引用方式
Java中有几种不同的引用方式,它们分别是:强引用、软引用、弱引用和虚引用。下面,我们首先详细地了解下这几种引用方式的意义。
在此之前我们介绍的内容中所使用的引用 都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java 虚拟机宁愿抛出 OutOfMemoryError 错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
软引用(SoftReference )
SoftReference 类的一个典型用途就是用于内存敏感的高速缓存。 SoftReference& 的原理是:在保持对对象的引用时保证在& JVM& 报告内存不足情况之前将清除所有的软引用。关键之处在于,垃圾收集器在运行时可能会(也可能不会)释放软可及对象。对象是否被释放取决于垃圾收集器的算法 以及垃圾收集器运行时可用的内存数量。
弱引用(WeakReference )
WeakReference 类的一个典型用途就是规范化映射( canonicalized mapping )。另外,对于那些生存期相对较长而且重新创建的开销也不高的对象来说,弱引用也比较有用。关键之处在于,垃圾收集器运行时如果碰到了弱可及对象,将释放& WeakReference& 引用的对象。然而,请注意,垃圾收集器可能要运行多次才能找到并释放弱可及对象。
虚引用(PhantomReference )
PhantomReference 类只能用于跟踪对被引用对象即将进行的收集。同样,它还能用于执行& pre-mortem& 清除操作。 PhantomReference& 必须与& ReferenceQueue& 类一起使用。需要& ReferenceQueue& 是因为它能够充当通知机制。当垃圾收集器确定了某个对象是虚可及对象时, PhantomReference& 对象就被放在它的& ReferenceQueue& 上。将& PhantomReference& 对象放在& ReferenceQueue& 上也就是一个通知,表明& PhantomReference& 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。 Reference与 ReferenceQueue 的配合使用。
GC、 Reference 与 ReferenceQueue 的交互
A、& GC无法删除存在强引用的对象的内存。
B、& GC发现一个只有软引用的对象内存,那么:
①& SoftReference对象的 referent& 域被设置为 null ,从而使该对象不再引用 heap 对象。
②& SoftReference引用过的 heap 对象被声明为 finalizable 。
③& 当 heap& 对象的& finalize()& 方法被运行而且该对象占用的内存被释放, SoftReference& 对象就被添加到它的& ReferenceQueue (如果后者存在的话)。
C、& GC发现一个只有弱引用的对象内存,那么:
①& WeakReference对象的 referent 域被设置为 null , 从而使该对象不再引用heap 对象。
②& WeakReference引用过的 heap 对象被声明为 finalizable 。
③& 当heap 对象的 finalize() 方法被运行而且该对象占用的内存被释放时, WeakReference 对象就被添加到它的 ReferenceQueue (如果后者存在的话)。
D、& GC发现一个只有虚引用的对象内存,那么:
①& PhantomReference引用过的 heap 对象被声明为 finalizable 。
②& PhantomReference在堆对象被释放之前就被添加到它的 ReferenceQueue 。
值得注意的地方有以下几点:
1、 GC 在一般情况下不会发现软引用的内存对象,只有在内存明显不足的时候才会发现并释放软引用对象的内存。
2、 GC 对弱引用的发现和释放也不是立即的,有时需要重复几次 GC ,才会发现并释放弱引用的内存对象。
3、软引用和弱引用在添加到 ReferenceQueue 的时候,其指向真实内存的引用已经被置为空了,相关的内存也已经被释放掉了。而虚引用在添加到 ReferenceQueue 的时候,内存还没有释放,仍然可以对其进行访问。
通过以上的介绍,相信您对Java 的引用机制以及几种引用方式的异同已经有了一定了解。光是概念,可能过于抽象,下面我们通过一个例子来演示如何在代码中使用 Reference 机制。
String str& =&& new& String( " hello " );& // ①&&
ReferenceQueue & String && rq& =&& new& ReferenceQueue & String & ();& // ②&&
WeakReference & String && wf& =&& new& WeakReference & String & (str, rq);& // ③&&
str =& // ④取消"hello"对象的强引用&&
String str1 = wf.get();& // ⑤假如"hello"对象没有被回收,str1引用"hello"对象&
// 假如"hello"对象没有被回收,rq.poll()返回null&&
Reference &?&& extends& String && ref = rq.poll();& // ⑥
在以上代码中,注意⑤⑥两处地方。假如“hello ”对象没有被回收 wf.get() 将返回“ hello ”字符串对象, rq.poll() 返回 null ;而加入“ hello ”对象已经被回收了,那么 wf.get() 返回 null , rq.poll() 返回 Reference 对象,但是此 Reference 对象中已经没有 str 对象的引用了 ( PhantomReference 则与WeakReference 、 SoftReference 不同 )。
引用机制与复杂数据结构的联合应用
了解了GC 机制、引用机制,并配合上 ReferenceQueue ,我们就可以实现一些防止内存溢出的复杂数据类型。
例如,SoftReference 具有构建 Cache 系统的特质,因此我们可以结合哈希表实现一个简单的缓存系统。这样既能保证能够尽可能多的缓存信息,又可以保证 Java 虚拟机不会因为内存泄露而抛出 OutOfMemoryError 。这种缓存机制特别适合于内存对象生命周期长,且生成内存对象的耗时比较长的情况,例如缓存列表封面图片等。对于一些生命周期较长,但是生成内存对象开销不大的情况,使用WeakReference 能够达到更好的内存管理的效果。
附SoftHashmap 的源码一份,相信看过之后,大家会对 Reference 机制的应用有更深入的理解。
package& com. *** .&
&&& // : SoftHashMap.java&&&
&&& import& java.util. * ;&&
&&& import& java.lang.ref. * ;&&
&&& import& android.util.L&
&&& public&& class& SoftHashMap& extends& AbstractMap& {&&
&&&&& /**& The internal HashMap that will hold the SoftReference.& */&&&
&&&&& private&& final& Map hash& =&& new& HashMap();&&
&&&&& /**& The number of "hard" references to hold internally.& */&&&
&&&&& private&& final&& int& HARD_SIZE;&&
&&&&& /**& The FIFO list of hard references, order of last access.& */&&&
&&&&& private&& final& LinkedList hardCache& =&& new& LinkedList();&&
&&&&& /**& Reference queue for cleared SoftReference objects.& */&&&
&&&&& private& ReferenceQueue queue& =&& new& ReferenceQueue();&&
&&&&& // Strong Reference number&&
&&&&& public& SoftHashMap()& {& this ( 100 ); }&&&
&&&&& public& SoftHashMap( int& hardSize)& { HARD_SIZE& =& hardS }&&&
&&&&& public& Object get(Object key)& {&&
&&&&&& Object result& =&&&&
&&&&&&& //& We get the SoftReference represented by that key&&&
&&&&&& SoftReference soft_ref& =& (SoftReference)hash.get(key);&&
&&&&&&& if& (soft_ref& !=&& null )& {&&
&&&&&&&&& //& From the SoftReference we get the value, which can be&&
&&&&&&&&& //& null if it was not in the map, or it was removed in&&
&&&&&&&&& //& the processQueue() method defined below&&&
&&&&&&& result& =& soft_ref.get();&&
&&&&&&&&& if& (result& ==&& null )& {&&
&&&&&&&&&&& //& If the value has been garbage collected, remove the&&
&&&&&&&&&&& //& entry from the HashMap.&&&
&&&&&&&&&& hash.remove(key);&&
&&&&&&&& }&& else&& {&&
&&&&&&&&&&& //& We now add this object to the beginning of the hard&&
&&&&&&&&&&& //& reference queue.& One reference can occur more than&&
&&&&&&&&&&& //& once, because lookups of the FIFO queue are slow, so&&
&&&&&&&&&&& //& we don't want to search through it each time to remove&&
&&&&&&&&&&& //& duplicates.&&
&&&&&&&&&&&&& // keep recent use object in memory&&
&&&&&&&&&& hardCache.addFirst(result);&&
&&&&&&&&&&& if& (hardCache.size()& && HARD_SIZE)& {&&
&&&&&&&&&&&&& //& Remove the last entry if list longer than HARD_SIZE&&&
&&&&&&&&&&&& hardCache.removeLast();&&
&&&&&&&&&& }&&&
&&&&&&&& }&&&
&&&&&& }&&&
&&&&&&& return&&&
&&&&& /**& We define our own subclass of SoftReference which contains&&
&&&&& not only the value but also the key to make it easier to find&&
&&&&& the entry in the HashMap after it's been garbage collected.& */&&&
&&&&& private&& static&& class& SoftValue& extends& SoftReference& {&&
&&&&&&& private&& final& O& //& always make data member final&&&
&&&&&&& /**& Did you know that an outer class can access private data&&
&&&&&&& members and methods of an inner class?& I didn't know that!&&
&&&&&&& I thought it was only the inner class who could access the&&
&&&&&&& outer class's private information.& An outer class can also&&
&&&&&&& access private members of an inner class inside its inner&&
&&&&&&& class.& */&&&
&&&&&&& private& SoftValue(Object k, Object key, ReferenceQueue q)& {&&
&&&&&&&&& super (k, q);&&
&&&&&&&&& this .key& =&&&
&&&&&& }&&&
&&&&& /**& Here we go through the ReferenceQueue and remove garbage&&
&&&&& collected SoftValue objects from the HashMap by looking them&&
&&&&& up using the SoftValue.key data member.& */&&&
&&&&& public&& void& processQueue()& {&&
&&&&&& SoftV&&
&&&&&&& while& ((sv& =& (SoftValue)queue.poll())& !=&& null )& {&&
&&&&&&&&&&& if (sv.get() ==&& null ) {&
&&&&&&&&&&&&&& Log.e( " processQueue " ,& " null " );&
&&&&&&&&&& } else {&
&&&&&&&&&&&&&& Log.e( " processQueue " ,& " Not null " );&
&&&&&&&&&& }&&
&&&&&&&& hash.remove(sv.key);& //& we can access private data!&&
&&&&&&&& Log.e( " SoftHashMap " ,& " release& "&& +& sv.key);&
&&&&&& }&&&
&&&&& /**& Here we put the key, value pair into the HashMap using&&
&&&&& a SoftValue object.& */&&&
&&&&& public& Object put(Object key, Object value)& {&&
&&&&&& processQueue();& //& throw out garbage collected values first&&&
&&&&&& Log.e( " SoftHashMap " ,& " put into& "&& +& key);&
&&&&&&& return& hash.put(key,& new& SoftValue(value, key, queue));&&
&&&&& public& Object remove(Object key)& {&&
&&&&&& processQueue();& //& throw out garbage collected values first&&&
&&&&&&& return& hash.remove(key);&&
&&&&& public&& void& clear()& {&&
&&&&&& hardCache.clear();&&
&&&&&& processQueue();& //& throw out garbage collected values&&&
&&&&& hash.clear();&&
&&&& public&& int& size()& {&&
&&&&& processQueue();& //& throw out garbage collected values first&&&
&&&&&& return& hash.size();&&
&&&& public& Set entrySet()& {&&
&&&&&& //& no, no, you may NOT do that!!! GRRR&&&
&&&&&& throw&& new& UnsupportedOperationException();&&
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 查找应用包名失败 的文章

 

随机推荐