java内存泄露和内存溢出

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 对象引用的对象已经结束,可供收集了。这使您能够刚好在对象占用的内存被回收之前采取行动。ReferenceReferenceQueue的配合使用。

GCReferenceReferenceQueue的交互

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

值得注意的地方有以下几点:

1GC在一般情况下不会发现软引用的内存对象,只有在内存明显不足的时候才会发现并释放软引用对象的内存。

2GC对弱引用的发现和释放也不是立即的,有时需要重复几次GC,才会发现并释放弱引用的内存对象。
3、软引用和弱引用在添加到ReferenceQueue的时候,其指向真实内存的引用已经被置为空了,相关的内存也已经被释放掉了。而虚引用在添加到ReferenceQueue的时候,内存还没有释放,仍然可以对其进行访问。

    代码示例

通过以上的介绍,相信您对Java的引用机制以及几种引用方式的异同已经有了一定了解。光是概念,可能过于抽象,下面我们通过一个例子来演示如何在代码中使用Reference机制。

1     String str =  new String("hello");  //
2     ReferenceQueue<String> rq =  new ReferenceQueue<String>();  //
3     WeakReference<String> wf =  new WeakReference<String>(str, rq);  //
4     str= null// ④取消"hello"对象的强引用
5     String str1=wf.get();  // ⑤假如"hello"对象没有被回收,str1引用"hello"对象
6       // 假如"hello"对象没有被回收,rq.poll()返回null
7     Reference<?  extends String> ref=rq.poll();  //


在以上代码中,注意⑤⑥两处地方。假如“hello”对象没有被回收wf.get()将返回“hello”字符串对象,rq.poll()返回null;而加入“hello”对象已经被回收了,那么wf.get()返回nullrq.poll()返回Reference对象,但是此Reference对象中已经没有str对象的引用了(PhantomReference则与WeakReferenceSoftReference不同)

    引用机制与复杂数据结构的联合应用

    了解了GC机制、引用机制,并配合上ReferenceQueue,我们就可以实现一些防止内存溢出的复杂数据类型。

例如,SoftReference具有构建Cache系统的特质,因此我们可以结合哈希表实现一个简单的缓存系统。这样既能保证能够尽可能多的缓存信息,又可以保证Java虚拟机不会因为内存泄露而抛出OutOfMemoryError。这种缓存机制特别适合于内存对象生命周期长,且生成内存对象的耗时比较长的情况,例如缓存列表封面图片等。对于一些生命周期较长,但是生成内存对象开销不大的情况,使用WeakReference能够达到更好的内存管理的效果。

SoftHashmap的源码一份,相信看过之后,大家会对Reference机制的应用有更深入的理解。

  1 package com.***.widget;
  2
  3 // : SoftHashMap.java 
  4 import java.util.*; 
  5 import java.lang.ref.*; 
  6
  7 import android.util.Log;
  8
  9 public  class SoftHashMap  extends AbstractMap 
 10  /** The internal HashMap that will hold the SoftReference. */ 
 11  private final Map hash = new HashMap(); 
 12  /** The number of "hard" references to hold internally. */ 
 13  private final int HARD_SIZE; 
 14  /** The FIFO list of hard references, order of last access. */ 
 15  private final LinkedList hardCache = new LinkedList(); 
 16  /** Reference queue for cleared SoftReference objects. */ 
 17  private ReferenceQueue queue = new ReferenceQueue(); 
 18
 19  //Strong Reference number
 20  public SoftHashMap() this(100); } 
 21  public SoftHashMap(int hardSize) { HARD_SIZE = hardSize; } 
 22  
 23
 24  public Object get(Object key) 
 25    Object result = null
 26    // We get the SoftReference represented by that key 
 27    SoftReference soft_ref = (SoftReference)hash.get(key); 
 28    if (soft_ref != null
 29      // From the SoftReference we get the value, which can be 
 30      // null if it was not in the map, or it was removed in 
 31      // the processQueue() method defined below 
 32      result = soft_ref.get(); 
 33      if (result == null
 34        // If the value has been garbage collected, remove the 
 35        // entry from the HashMap. 
 36        hash.remove(key); 
 37      }
 else 
 38        // We now add this object to the beginning of the hard 
 39        // reference queue.  One reference can occur more than 
 40        // once, because lookups of the FIFO queue are slow, so 
 41        // we don't want to search through it each time to remove 
 42        // duplicates. 
 43          //keep recent use object in memory
 44        hardCache.addFirst(result); 
 45        if (hardCache.size() > HARD_SIZE) 
 46          // Remove the last entry if list longer than HARD_SIZE 
 47          hardCache.removeLast(); 
 48        }
 
 49      }
 
 50    }
 
 51    return result; 
 52  }
 
 53
 54  /** We define our own subclass of SoftReference which contains 
 55   not only the value but also the key to make it easier to find 
 56   the entry in the HashMap after it's been garbage collected. */
 
 57  private static class SoftValue extends SoftReference 
 58    private final Object key; // always make data member final 
 59    /** Did you know that an outer class can access private data 
 60     members and methods of an inner class?  I didn't know that! 
 61     I thought it was only the inner class who could access the 
 62     outer class's private information.  An outer class can also 
 63     access private members of an inner class inside its inner 
 64     class. */
 
 65    private SoftValue(Object k, Object key, ReferenceQueue q) 
 66      super(k, q); 
 67      this.key = key; 
 68    }
 
 69  }
 
 70
 71  /** Here we go through the ReferenceQueue and remove garbage 
 72   collected SoftValue objects from the HashMap by looking them 
 73   up using the SoftValue.key data member. */
 
 74  public void processQueue() 
 75    SoftValue sv; 
 76    while ((sv = (SoftValue)queue.poll()) != null
 77        if(sv.get()== null){
 78            Log.e("processQueue", "null");
 79        }
else{
 80            Log.e("processQueue", "Not null");
 81        }

 82      hash.remove(sv.key); // we can access private data!
 83      Log.e("SoftHashMap", "release " + sv.key);
 84    }
 
 85  }
 
 86  /** Here we put the key, value pair into the HashMap using 
 87   a SoftValue object. */
 
 88  public Object put(Object key, Object value) 
 89    processQueue(); // throw out garbage collected values first 
 90    Log.e("SoftHashMap", "put into " + key);
 91    return hash.put(key, new SoftValue(value, key, queue)); 
 92  }
 
 93  public Object remove(Object key) 
 94    processQueue(); // throw out garbage collected values first 
 95    return hash.remove(key); 
 96  }
 
 97  public void clear() 
 98    hardCache.clear(); 
 99    processQueue(); // throw out garbage collected values 
100    hash.clear(); 
101  }
 
102  public int size() 
103    processQueue(); // throw out garbage collected values first 
104    return hash.size(); 
105  }
 
106  public Set entrySet() 
107    // no, no, you may NOT do that!!! GRRR 
108    throw new UnsupportedOperationException(); 
109  }
 
110}
 
111
112
113
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值