| 
                        副标题[/!--empirenews.page--]
                         之前我们提到过 GC,但当 Java 中引用的对象越来越多,会导致内存空间不足,最终会产生错误  OutOfMemoryError,并让应用程序终止。那为什么 GC 在此时不能多收集一些对象呢?这就和今天说的引用类型有关了。 
首先,从 JDK1.2  开始,对象的引用被划分为4种级别,从而使程序能更加灵活地控制对象的生命周期。这4种级别由高到低依次为:强引用、软引用、弱引用和虚引用。 
强引用 
强引用(Strong Reference)是使用最普遍的引用。如果一个对象具有强引用,那么它永远不会被 GC。例如: 
- Object strongReference = new Object(); 
 
  
当内存空间不足时,JVM 宁愿抛出OutOfMemoryError,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 
如果强引用对象不使用时,需要弱化从而可以被 GC,例如ArrayList中的clear()方法: 
- /** 
 - * Removes all of the elements from this list. The list will 
 - * be empty after this call returns. 
 - */ 
 - public void clear() { 
 - modCount++; 
 -  
 - // clear to let GC do its work 
 - for (int i = 0; i < size; i++) 
 - elementData[i] = null; 
 -  
 - size = 0; 
 - } 
 
  
显式地设置强引用对象为null,或让其超出对象的生命周期范围,则垃圾回收器认为该对象不存在引用,就会回收这个对象。具体什么时候收集这要取决于具体的垃圾回收器。 
软引用 
如果一个对象只具有软引用(Soft  Reference),当内存空间充足时,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。让我们来看一个例子具体了解一下: 
- String str = new String("abc"); 
 - SoftReference<String> softReference = new SoftReference<>(str); 
 - String result = softReference.get(); 
 
  
让我们来看一下get(): 
- public T get() { 
 - T o = super.get(); 
 - // timestamp代表上一次软引用上一次被使用的时间(初始化、get()) 
 - // clock代表上一次GC的时间 
 - if (o != null && this.timestamp != clock) 
 - this.timestamp = clock; 
 - return o; 
 - } 
 
  
因此,软引用在被垃圾回收时,也遵循LRU法则,优先回收最近最少被使用的对象进行回收。 
软引用的使用场景多是内存敏感的高速缓存。具体来说,就是我们希望将数据存放到缓存中,这样可以快速进行读取。但是,当 JVM  中内存不够用时,我们又不希望缓存数据会占用到 JVM 的内存。例如配合ReferenceQueue,如果软引用所引用对象被垃圾回收,JVM  就会把这个软引用加入到与之关联的引用队列中: 
- ReferenceQueue<String> referenceQueue = new ReferenceQueue<>(); 
 - String str = new String("abc"); 
 - SoftReference<String> softReference = new SoftReference<>(str, referenceQueue); 
 -  
 - str = null; 
 - // Notify GC 
 - System.gc(); 
 -  
 - System.out.println(softReference.get()); // abc 
 -  
 - Reference<? extends String> reference = referenceQueue.poll(); 
 - System.out.println(reference); //null 
 
  
但是需要注意的是,如果使用软引用缓存,有可能导致Full GC增多。 
弱引用 
如果一个对象只具有弱引用(Weak  Reference),其生命周期相比于软引用更加短暂。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会对它进行回收。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。其使用为: 
- String str = new String("abc"); 
 - WeakReference<String> weakReference = new WeakReference<>(str); 
 - str = weakReference.get(); 
 
  
讲到弱引用,就不得不提到WeakHashMap。和HashMap相比,当我们给 JVM 分配的内存不足的时候,HashMap 宁可抛出  OutOfMemoryError 异常,也不会回收其相应的没有被引用的对象,而 WeakHashMap 则会回收存储在其中但有被引用的对象。 
WeakHashMap 通过将一些没有被引用的键的值赋值为 null ,这样的话就会告知GC去回收这些存储的值了。假如我们特地传入 key 为 null  的键,WeakHashMap 会将键设置为特殊的 Oject,源码为: 
- public V put(K key, V value) { 
 - // key会被重新赋值 
 - Object k = maskNull(key); 
 - int h = hash(k); 
 - Entry<K,V>[] tab = getTable(); 
 - int i = indexFor(h, tab.length); 
 -  
 - for (Entry<K,V> e = tab[i]; e != null; ee = e.next) { 
 - if (h == e.hash && eq(k, e.get())) { 
 - V oldValue = e.value; 
 - if (value != oldValue) 
 - e.value = value; 
 - return oldValue; 
 - } 
 - } 
 -  
 - modCount++; 
 - Entry<K,V> e = tab[i]; 
 - tab[i] = new Entry<>(k, value, queue, h, e); 
 - if (++size >= threshold) 
 - resize(tab.length * 2); 
 - return null; 
 - } 
 -  
 - /** 
 - * Value representing null keys inside tables. 
 - * 特殊的key 
 - */ 
 - private static final Object NULL_KEY = new Object(); 
 -  
 - /** 
 - * Use NULL_KEY for key if it is null. 
 - */ 
 - private static Object maskNull(Object key) { 
 - return (key == null) ? NULL_KEY : key; 
 - } 
 
  
虚引用 
虚引用(PhantomReference),顾名思义,就是形同虚设。与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 
虚引用主要用来跟踪对象被垃圾回收器回收的活动。 虚引用与软引用和弱引用的一个区别在于: 
                        (编辑:我爱故事小小网_铜陵站长网) 
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! 
                     |