`

深入理解WeakHashmap

    博客分类:
  • java
 
阅读更多

引自http://mikewang.blog.51cto.com/3826268/880775

WeakHashmap

(一) 查看API文档,WeakHashmap要点如下:

1. 以弱键 实现的基于哈希表的 Map。在 WeakHashMap 中,当某个键不再正常使用时,将自动移除其条目。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。丢弃某个键时,其条目从映射中有效地移除

2. WeakHashMap 类的行为部分取决于垃圾回收器的动作。因为垃圾回收器在任何时候都可能丢弃键,WeakHashMap 就像是一个被悄悄移除条目的未知线程。特别地,即使对 WeakHashMap 实例进行同步,并且没有调用任何赋值方法,在一段时间后 size 方法也可能返回较小的值,对于 isEmpty 方法,返回 false,然后返回true,对于给定的键,containsKey 方法返回 true 然后返回 false,对于给定的键,get 方法返回一个值,但接着返回 null,对于以前出现在映射中的键,put 方法返回 null,而 remove 方法返回 false,对于键 set、值 collection 和条目 set 进行的检查,生成的元素数量越来越少。

3. WeakHashMap 中的每个键对象间接地存储为一个弱引用的指示对象。因此,不管是在映射内还是在映射之外,只有在垃圾回收器清除某个键的弱引用之后,该键才会自动移除。

(二) 引用对象的四种分类:

Api图片如下:

1. 强引用(Strong Reference)

2. 弱引用(Weak Reference)

3. 软引用(Soft Reference)

4. 幻象引用(Phantom Reference)

(三) 深入理解

至此,对于WeakHashMap有了一个基本概念,但是还是比较模糊。找到一篇英文文档,将要点总结如下(如有翻译不对,请指出,谢谢):

1. 强引用

强引用就是普通的Java引用,代码:

  1. StringBuffer buffer = new StringBuffer(); 

这句代码创建了一个StringBuffer对象,在变量buffer中存储了这个对象的一个强引用。强引用之所以称之为“强”(Strong),是因为他们与垃圾回收器(garbage collector)交互的方式。特别是(specifically),如果一个对象通过强引用连接(strongly reachable-强引用可到达),那么它就不在垃圾回收期处理之列。当你正在使用某个对象而不希望垃圾回收期销毁这个对象时,强引用通常正好能满足你所要的。

2. 当强引用太强的时候

假定你要使用一个final类Widget,但是基于某种原因,你不能继承(extend)这个类或者通过其他方法为这个类增加一些新的功能。如果你需要跟踪(track)这个类的不同对象的序列号。那么可以将这些对象放入HashMap中,获得不同的value值,这样就可以做到通过不同的value值跟踪这些对象了。代码: 

  1. serialNumberMap.put(widget, widgetSerialNumber); 

但是widget的强引用会产生一些问题。在我们不需要一个Widget的序列号时,我们需要将这个Widget对应的Entry从HashMap中移除。否则我们可能面临内存泄露(memory leak)的问题(如果我们没有在应当移除Widgt的时候移除它),或者我们将莫名其妙的丢失序列号(如果我们正在使用Widget时却移除了它)。如果这些问题类似,那么这些问题是无垃圾回收机制(non-garbage-collected language)的编程语言的开发者所面临的问题。Java的开发者不需要担心这种问题。

W如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

强引用的另外一个常见问题就是图片缓存(cache)。普通的强引用将使得Image继续保存在内存中。在一些情况下,我们不需要有些Image继续留在内存中,我们需要将这些图片从内存中移出,这时,我们将扮演垃圾回收期的角色来决定哪些照片被移除。使这些被移出的图片被垃圾回收器销毁。下一次,你被迫再次扮演垃圾回收期的角色,手动决定哪些Image被回收。

Note:我觉得也可以用对象的hashCode来跟踪对象。作者在此所举的例子,只在说明Strong Reference。

3. 弱引用

简单说,就是弱引用不足以将其连接的对象强制保存在内存中。弱引用能够影响(leverage)垃圾回收器的某个对象的可到达级别。代码:

  1. WeakReference<Widget> weakWidget = new WeakReference<Widget>(widget); 

你可以使用weakWidget.get()方法老获取实际的强引用对象。但是在之后,有可能突然返回null值(如果没有其他的强引用在Widget之上),因为这个弱引用被回收。其中包装的Widget也被回收。

解决Widget序列号的问题,最简单的方法就是使用WeakHashmap。其key值为弱引用。如果一个WeakHashmap的key变成垃圾,那么它对应用的value也自动的被移除。

W:垃圾回收期并不会总在第一次就找到弱引用,而是会找几次才能找到。

4. 引用队列(Reference Quene)

一旦弱引用返回null值,那么其指向的对象(即Widget)就变成了垃圾,这个弱引用对象(即weakWidget)也就没有用了。这通常意味着要进行一定方式的清理(cleanup)。例如,WeakHashmap将会移除一些死的(dread)的entry,避免持有过多死的弱引用。

ReferenceQuene能够轻易的追踪这些死掉的弱引用。可以讲ReferenceQuene传入WeakHashmap的构造方法(constructor)中,这样,一旦这个弱引用指向的对象成为垃圾,这个弱引用将加入ReferenceQuene中。

如下图所示:

5. 软引用

除了在抛出自己所指向的对象的迫切程度方面不一样之外,软引用和弱引用基本一样。一个对象为弱可到达(或者指向这个对象的强引用是一个弱引用对象-即强引用的弱引用封装),这个对象将在一个垃圾回收循环内被丢弃。但是,弱引用对象会保留一段时间之后才会被丢弃。

软引用的执行和弱引用并没有任何不同。但是,在供应充足(in plentiful supply)的情况下,软可到达对象将在内存中保存尽可能长的时间。这使得他们在内存中有绝佳的存在基础(即有尽可能长存在的基础)。因为你让垃圾回收器去担心两件事情,一件是这个对象的可到达性,一件是垃圾回收期多么想要这些对象正在消耗的内存。

6. 幻象引用(phantom reference)

幻象引用于弱引用和软引用均不同。它控制其指向的对象非常弱(tenuous),以至于它不能获得这个对象。get()方法通常情况下返回的是null值。它唯一的作用就是跟踪列队在ReferenceQuene中的已经死去的对象。

幻象引用和弱引用的不同在于其入队(enquene)进入ReferenceQuene的方式。当弱引用的对象成为若可到达时,弱引用即列队进入ReferenceQuene。这个入队发生在终结(finialize)和垃圾回收实际发生之前。理论上,通过不正规(unorthodox)的finilize()方法,成为垃圾的对象能重新复活(resurrected),但是弱引用仍然是死的。幻象引用只有当对象在物理上从内存中移出时,才会入队。这就阻止我们重新恢复将死的对象。

W:终结(Finalization)指比拉圾回收更一般的概念,可以回收对象所占有的任意资源,比如文件描述符和图形上下文等。

幻象引用由两个好处:

A:它能确定某一个对象从内存中移除的时间,这也是唯一的方式。通常情况下,这不是非常有用。但是迟早(come in handy)会用到手动处理大图片的情况:如果你确定一张图片需要被垃圾回收,那么在你尝试加载下一张照片前,你应该等待这张照片被回收完成。这样就使得令人恐惧的(dreaded)内存溢出不太可能发生。

B:虚幻引用能够避终结(finilize)的基本问题。finilize()方法能够通过给一个垃圾对象关联一个强引用使之复活。问题是覆写了finilize()方法的对象在成为垃圾之前,为了回收,垃圾回收期需要执行两次单独的循环。第一轮循环确定某个对象是垃圾,那么它就符合终结finilize的条件。在finilize的过程中,这个对象可能被“复活”。在这个对象被实际移除之前,垃圾回收期不得不重新运行一遍。因为finilization并不是实时调用的,所以在终止进行的过程中,可能发生了gc的多次循环。在实际清理垃圾对象时,这导致了一些延时滞后。这将导致Heap中有大量的垃圾导致内存溢出。

幻象引用不可能发生以上的情况,当幻象引用入队时,它实际上已经被移除了内存。幻象内存无法“复活”对象。这发现这个对象时虚幻可到达时,在第一轮循环中,它就被回收。

可以证明,finilize()方法从不在第一种情况下使用,但是虚幻引用提供了一种更安全和有效的使用和被排除掉的finilize方法的机制,使得垃圾回收更加简单。但是因为有太多的东西需要实现,我通常不适用finilize。

W:Object类中相关内容如下:

文档中相关内容如下:

(四) 原文地址及其他翻译

原文地址:http://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html

其他翻译地址:http://blog.csdn.net/fancyerii/article/details/5610360

本文出自 “小新专栏” 博客,请务必保留此出处http://mikewang.blog.51cto.com/3826268/880775

分享到:
评论

相关推荐

    预习,2、内存分配与回收策略~深入理解垃圾回收器1

    内存分配与回收是编程语言中一个关键的概念,特别是在Java这样的自动管理内存的语言中。...在实际开发中,比如使用WeakHashMap或ThreadLocal,就是利用了弱引用和虚引用的特点,以实现特定的功能需求。

    线程死锁CPU过高,请求原因分析

    线程死锁是多线程编程中一个严重的问题,它发生在两个或多个线程相互等待对方释放资源,导致它们都无法继续执行。...开发者需要深入理解线程同步机制、弱引用的特性以及性能优化技巧,以确保应用程序的稳定性和效率。

    深入理解Java中的弱引用

    Java 提供了 `WeakHashMap` 类,它的键使用弱引用,这样当键所对应的对象不再被其他强引用时,键及其关联的值都会被自动清除,从而避免了内存泄漏。 虚引用(Phantom Reference)是最弱的引用类型,它甚至无法获取...

    java缓存技术深入剖析

    Javaeye创始人分享的这份“java缓存技术深入剖析”旨在帮助开发者更好地理解和应用缓存机制。以下是对该主题的详细阐述: 一、缓存的基本概念 缓存是一种存储技术,用于临时存储常用数据,以减少对主存储器(如硬盘...

    JAVA面试葵花宝典

    2. 继承与多态:深入理解单继承和多态性,了解super和this关键字的用法。 3. 接口:掌握接口的概念,接口的实现与多接口实现。 4. 抽象类与抽象方法:理解抽象类和抽象方法的意义,何时使用它们。 5. 包:理解包的...

    JAVA面试常见题型全集

    3. Map接口:理解键值对存储,了解ConcurrentHashMap和WeakHashMap的特性。 4. 集合操作:熟练使用add、remove、contains、clear等方法,以及集合的遍历方式。 五、多线程 1. 线程基础:理解线程的生命周期,掌握...

    2013年java开发最常见的笔试面试题大总结

    2. 数据类型:深入理解基本数据类型和引用数据类型,以及它们在栈和堆内存中的存储方式。 3. 面向对象:掌握封装、继承和多态的基本概念,理解类与对象的关系,以及抽象类和接口的使用场景。 4. 构造器:了解构造器...

    张孝祥java就业面试题宝典

    2. 数据类型与变量:深入理解基本数据类型和引用数据类型,了解变量的作用域和生命周期。 3. 运算符与流程控制:掌握各种运算符的用法,如赋值、比较、逻辑等,以及if语句、switch语句、for循环、while循环的运用。 ...

    2018最新Java面试题详细版.zip_2018 面试_E98_Java面试题2018_java2018面试_java面试

    以上是2018年Java面试中可能涉及的关键知识点,对于每一个知识点的深入理解和实践操作都是面试成功的关键。在准备面试时,不仅要理解理论,还要通过编写代码来巩固这些知识,以便在实际问题中能够灵活运用。

    java面试题 学习笔记

    3. 多态:深入理解接口和抽象类,以及多态在方法重写和重载中的应用。 4. 构造器:掌握构造函数的作用,以及this关键字的用法。 5. 接口与内部类:理解接口的实现,静态内部类,匿名内部类,以及成员内部类的应用。 ...

    2013java面试题收集

    2. 数据类型:深入理解基本数据类型及其区别,包括引用类型的动态性。 3. 变量与常量:掌握变量的声明、初始化和作用域,了解常量的概念和使用。 4. 流程控制:熟悉if、switch、for、while等控制结构,以及break和...

    SCJP Sun Certified Programmer for java 6 Study Guide(Exam 310-065)

    该书旨在帮助考生深入理解和掌握Java 6编程语言的核心概念和技术,从而顺利通过310-065认证考试。 1. **Java基础** - **数据类型**:包括基本数据类型和引用数据类型,如int、char、boolean、String等。 - **变量...

    java面试常问基础知识总结(超经典)

    Java作为一门广泛使用的编程语言,其面试基础知识涵盖了众多领域,包括但不限于语法、数据结构、算法、多线程、集合框架、异常处理、IO流、网络编程等。...不断深入理解和实践,对于成为一名优秀的Java开发者至关重要。

    java数据结构课件与分析

    6. **映射(Map)**:理解键值对的概念,学习HashMap、TreeMap和WeakHashMap等映射类的实现和差异。 7. **排序和搜索算法**:包括冒泡排序、快速排序、归并排序、二分查找等。了解这些算法的原理和Java实现,以及...

    Map-main-源码.rar

    《深入解析Map的主要实现原理...深入理解这些类的源码,可以帮助我们更好地利用它们,并在设计和优化系统时做出更明智的选择。对于开发者来说,熟悉并掌握这些数据结构的实现原理,无疑会提升编程技能和问题解决能力。

    一个讲解很清晰的Java集合框架PPT

    这个“一个讲解很清晰的Java集合框架PPT”显然是一个对外公开的教育资源,旨在帮助学习者深入理解Java集合的概念、结构以及实际应用。 在Java中,集合框架主要包括四大接口:List、Set、Queue和Map。每个接口都有...

    request包装的,实现request属性共享内存管理

    要深入理解这个实现,你需要阅读`RemoteSessionRequest.java`的源代码,查看它是如何创建、初始化、存储和检索属性的,以及它是如何处理并发问题的。此外,理解Web应用的整体架构,尤其是与会话管理和请求处理相关的...

    listview获取网络图片缓存优化

    在Android开发中,ListView是一种常见的组件,用于展示大量的列表数据。然而,当列表项中包含网络图片时,如果没有进行适当的优化,可能会导致性能问题,如滚动卡顿、...源码阅读和实践是深入理解这些优化的关键步骤。

    java集合与通用集合

    对于Java开发者来说,深入学习和实践集合框架是非常必要的,这有助于提升软件质量和开发速度。在实际工作中,根据需求选择合适的集合类型,并利用辅助类提供的方法优化代码,是成为一个高效Java程序员的关键。

Global site tag (gtag.js) - Google Analytics