`

引用类,WeakHashMap,以及让value自动回收

阅读更多
   如果要彻底明白WeakHashMap这个类,需要联系GC和对象的可触及状态(强可触及、软可触及……)来看,可参考JVM规范里相关内容。
关于gc和对象可触及性这两块,这里我就不展开了。不过,如果要看懂本文,最好还是先去看下这两块的机制。
  本文分三块:
  1、jdk引用类介绍(如WeakReference)
  2、WeakHashMap工作机制介绍
  3、自己实现一个类,让它可以自动回收value的堆区(自认为这是本文亮点

PS:本文有误,value的堆区也会自动回收,因为在调用put方法的时候,内部调用了getTable方法,而getTable方法内部又调用了expungeStaleEntries方法,在expungeStaleEntries方法内部处理了已经由gc的后台线程Reference Handler加入到ReferenceQueue<K>中的Reference对象,该对象的内部的value被指向null,从而提示gc未来可回收value原对象的堆区空间了。
故本文第三条完全没有必要,WeakHashMap本身已经能很好的回收value的堆区了,当初不知为何有那样的测试结果出来,抱歉了!各位


1、jdk引用类介绍

而jdk里的引用类体系为:

以软引用为例,看下引用的内存结构:


而,对应各种可触及性有很多引用类型
   1、强可触及性
   2、软可触及性----SoftReference
   3、弱可触及性--WeakReference
   4、可复活性---FinalReference
   5、影子可触及性(译法可不同)---PhantomReference
   6、不可触及性
引用类的学习,如果需要详细资料,请参考:
弱引用:http://www.ibm.com/developerworks/cn/java/j-jtp11225/
软引用:http://www.ibm.com/developerworks/cn/java/j-jtp01246.html
引用类使用指南:https://www.ibm.com/developerworks/cn/java/j-refs/
《深入Java虚拟机》
尤其前三篇IBM开发社区的文章,分析的相当到位!!!
好了,下面正式开始谈WeakHashMap



2、WeakHashMap工作机制介绍:
      这里用简单的话写出,可能不能完全描述清晰,尤其对初学者而言。先这样写着,如果需要,我会专门写一篇WeakHashMap源码分析文章,然后附上链接,那就看大家需不需要了。
      在put一个新pair的时候,实际上是将key的引用封装成了一个 WeakReference<K>对象(这不同于HashMap中的直接使用key作为Entry的属性)。于是在每次调用WeakHashMap的
        
 gettable()
          size()
          resize()


方法的时候都会调用expungStaleEntries()方法来清除处理已经被gc加入到队列中的弱引用。处理方法见expungStaleEntries方法体:

private void expungeStaleEntries() {
	Entry<K,V> e;
        while ( (e = (Entry<K,V>) queue.poll()) != null) {
            int h = e.hash;
            int i = indexFor(h, table.length);

            Entry<K,V> prev = table[i];
            Entry<K,V> p = prev;
            while (p != null) {
                Entry<K,V> next = p.next;
                if (p == e) {
                    if (prev == e)
                        table[i] = next;
                    else
                        prev.next = next;
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                    break;
                }
                prev = p;
                p = next;
            }
        }
}

上面这段代码实际上做的工作是:将已经被加入队列中的弱引用对应的Entry的从整个map的结构中移除,然后断开Entry指向 value的引用,加速gc回收value的堆区空间。而key指向的堆区对象已经在这个引用对象本身被GC加入到queue之前已经被释放了所有所有的弱引用,进入可复活状态或者已经经过可复活状态等待被回收了。


3、自己实现一个类,让它可以自动回收value的堆区
不过,WeakHashMap的设计有一个地方让我们不爽,如果我们没有调用size()方法,value在堆区的空间就不会被释放。于是我写了一个类MyWeakHashMap来替代WeakHashMap:
如果要获得完整代码,请下载附件。
/**
 * 自己实现的类,替代jdk中的类java.util.WeakHashMap。
 * 和WeakHashMap比较,无需调用该java.util.WeakHashMap
 * 中的size()等方法,该类可以自动释放内部类Entry中的
 * value的堆空间。
 * @author 贾懂凯 
 * 
 * @param <K>
 * @param <V>
 */
public class MyWeakHashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>{
	 //如果有兴趣,请下载运行
}


附件中同时有一个测试类Test,通过测试,能很明确地看出我设计的类和jdk自带的WeakHashMap类的区别。
下面给出测试代码和结果:
如果是jdk自带类WeakHashMap:
import java.util.ArrayList;
import java.util.WeakHashMap;
import java.util.List;
public class Test {
	public static void main(String args[]){
		
		//测试1
		
		 List<WeakHashMap<byte[][], byte[][]>> maps = new ArrayList<WeakHashMap<byte[][], byte[][]>>(); 
		 for (int i = 0; i < 1000; i++) {  
		        WeakHashMap<byte[][], byte[][]> d = new WeakHashMap<byte[][], byte[][]>();  
		        d.put(new byte[1000][1000], new byte[1000][1000]);  
		        maps.add(d);  
		        System.gc();  
		        System.err.println(i);  
		    } 
	}
}

结果
写道
0
1
……
63

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at Test.main(
Test.java:18)

我们发先报出了OOM(内存溢出)异常。使用我定义的类,就不会出现OOM:


import java.util.WeakHashMap;
import java.util.List;
public class Test {
	public static void main(String args[]){
		//测试2
		 List<MyWeakHashMap<byte[][], byte[][]>> maps = new ArrayList<MyWeakHashMap<byte[][], byte[][]>>();  
		 for (int i = 0; i < 1000; i++) {  
		        MyWeakHashMap<byte[][], byte[][]> d = new MyWeakHashMap<byte[][], byte[][]>();  
		        d.put(new byte[1000][1000], new byte[1000][1000]);  
		        maps.add(d);  
		        System.gc();  
		        System.err.println(i);  
		    } 
	}
}

结果:
写道
0
1
2
3
……

不会出现OOM(内存溢出)异常。






  • 大小: 38.2 KB
  • 大小: 13.1 KB
分享到:
评论

相关推荐

    WeakHashMap的使用方法详解

    WeakHashMap是Java中的一种哈希映射表,它的键是弱引用的,意味着当 WeakHashMap 的键对象只有 WeakHashMap 自己持有时,垃圾回收器可以将其回收。WeakHashMap 的使用方法主要体现在以下几个方面: 1. WeakHashMap...

    Java弱引用与WeakHashMap

    在《Effective Java 2nd Edition》中,第6条“消除过期的对象引用”提到,虽然Java有垃圾回收机制,但是只要是自己管理的内存,应该警惕内存泄露的问题,例如的对象池、缓存中的过期对象都有可能引发内存泄露的问题...

    java集合-WeakHashMap的使用

    WeakHashMap是Java中的一种特殊的哈希表实现,它使用弱引用(Weak Reference)来保存键对象。当键对象没有被其他强引用引用时,在垃圾回收时会自动从WeakHashMap中移除对应的键值对。

    Java引用类型1

    - 使用`WeakHashMap`可以自动管理弱引用键,当键对象被回收时,对应的条目也会自动删除。 4. **虚引用(Phantom Reference)** - 虚引用是最弱的一种引用,不能直接获取引用对象,只能通过引用队列。虚引用对象在...

    Java编程WeakHashMap实例解析

    WeakHashMap是Java编程中的一种特殊的HashMap实现,它使用弱引用来保存键和值,这样可以使得垃圾回收器自动清理键和值。在WeakHashMap中,键和值都是弱引用的,这样可以避免内存泄露的问题。 WeakHashMap的实现...

    Java中弱引用和软引用的区别以及虚引用和强引用介绍

    - **WeakHashMap**:这个特殊的Map实现使用弱引用作为键,当键的强引用消失时,键值对将自动从映射中移除,有助于防止内存泄漏。 - **资源清理**:虚引用配合引用队列可以实现对象回收后的资源清理,例如关闭文件流...

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

    内存分配与回收是编程语言中一个关键的概念,特别是在Java这样的自动管理内存的语言中。Java的垃圾回收机制(Garbage Collection, GC)是它与C++等语言的主要技术区别之一。理解GC的工作原理和内存分配策略对于优化...

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

    在Java编程中,WeakHashMap是一种特殊的哈希表,它的键(Key)是弱引用,当键被垃圾回收器清除后,即使有值(Value)存在,该条目也会自动从哈希表中移除。 线程死锁的原因通常包括以下几点: 1. **资源互斥**:每...

    java 引用相关文档

    在这里,我们将详细讲解Java中的四种引用类型:强引用、软引用、弱引用和虚引用,以及它们在内存管理和垃圾收集中的作用。 1. **强引用(Strong Reference)** - 强引用是Java中最常见的引用类型,它是默认的引用...

    详解Java对象的强、软、弱和虚引用+ReferenceQueue

    WeakHashMap是弱引用map,就是Key键是一个弱引用的键,如果Key键被回收,则在get该map中值后,会自动remove掉value。如果Key键始终被强引用,则是无法被回收的;注意Value是被强引用的,所以不要让Value间接的引用了...

    常见的内存泄漏原因及解决方法 - 简书1

    要避免这种情况,可以使用WeakHashMap,它的键使用WeakReference,当对象不再被其他地方引用时,键会自动从集合中移除。 6. 自定义View持有可能导致泄漏的引用 自定义View在绘制过程中可能会持有外部对象的引用,...

    10分钟带你理解Java中的弱引用

    总结,弱引用在Java中提供了一种优雅的方式,允许程序员在需要时释放不再使用的对象,避免内存泄漏,同时让垃圾收集器自动管理内存。理解和合理使用弱引用对于编写高效、健壮的Java应用程序至关重要。

    Java理论与实践:用弱引用堵住内存泄漏

    总的来说,本文深入浅出地讲解了Java中的弱引用机制,以及如何利用弱引用来管理和防止内存泄漏。弱引用作为一种强大的工具,可以有效地处理那些生命周期不确定或需要灵活管理的对象,避免过度占用内存资源,保持程序...

    Java通过What、Why、How了解弱引用

    在Java编程语言中,弱引用是一种特殊的引用类型,它允许...通过WeakReference类以及相关数据结构如WeakHashMap,Java为开发者提供了实现这一目标的工具。在实际应用中,合理使用弱引用能够提升程序的性能和稳定性。

    深入理解Java中的弱引用

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

    ry08-06.pdf

    弱表格中,键(key)与值(value)之间的循环引用会导致垃圾收集器无法收集这些元素,即使它们从外部不再可达。这在某些类型的应用中带来了困难。循环引用在弱表格中阻止了元素的回收,导致内存泄漏。 解决弱表格中...

    弱类型语言允许将一块内存看做多种类型

    - **垃圾回收机制**:当一个 WeakHashMap 中的键不再被其他地方引用时,系统执行垃圾回收后,该键就会被从 WeakHashMap 中自动移除。 - **expungeStaleEntries 方法**:为了确保 WeakHashMap 的键被正确清理,每当...

    smartref:Java 1.5+ 的简单引用类型和容器

    在Java 1.5及以后的版本中,除了基础的强引用(Strong Reference)之外,引入了弱引用(Weak Reference)、软引用(Soft Reference)和虚引用(Phantom Reference)等智能引用类型,以及与之相关的容器类,以帮助...

Global site tag (gtag.js) - Google Analytics