精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

面試中經(jīng)常被問(wèn)到Java引用類型原理,帶你深入剖析

開(kāi)發(fā) 后端
本篇文章主要是分析軟引用、弱引用、虛引用的實(shí)現(xiàn),這三種引用類型都是繼承于Reference這個(gè)類,主要邏輯也在Reference中。

1.選擇唯一性索引

唯一性索引的值是唯一的,可以更快速的通過(guò)該索引來(lái)確定某條記錄。例如,學(xué)生表中學(xué)號(hào)是具有唯一性的字段。為該字段建立唯一性索引可以很快的確定某個(gè)學(xué)生的信息。如果使用姓名的話,可能存在同名現(xiàn)象,從而降低查詢速度。

2.為經(jīng)常需要排序、分組和聯(lián)合操作的字段建立索引

經(jīng)常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作會(huì)浪費(fèi)很多時(shí)間。如果為其建立索引,可以有效地避免排序操作。

3.為常作為查詢條件的字段建立索引

如果某個(gè)字段經(jīng)常用來(lái)做查詢條件,那么該字段的查詢速度會(huì)影響整個(gè)表的查詢速度。因此,為這樣的字段建立索引,可以提高整個(gè)表的查詢速度。

4.限制索引的數(shù)目

索引的數(shù)目不是越多越好。每個(gè)索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大。修改表時(shí),對(duì)索引的重構(gòu)和更新很麻煩。越多的索引,會(huì)使更新表變得很浪費(fèi)時(shí)間。

5.盡量使用數(shù)據(jù)量少的索引

如果索引的值很長(zhǎng),那么查詢的速度會(huì)受到影響。例如,對(duì)一個(gè)CHAR(100)類型的字段進(jìn)行全文檢索需要的時(shí)間肯定要比對(duì)CHAR(10)類型的字段需要的時(shí)間要多。

6.盡量使用前綴來(lái)索引

如果索引字段的值很長(zhǎng),最好使用值的前綴來(lái)索引。例如,TEXT和BLOG類型的字段,進(jìn)行全文檢索會(huì)很浪費(fèi)時(shí)間。如果只檢索字段的前面的若干個(gè)字符,這樣可以提高檢索速度。

7.刪除不再使用或者很少使用的索引

表中的數(shù)據(jù)被大量更新,或者數(shù)據(jù)的使用方式被改變后,原有的一些索引可能不再需要。數(shù)據(jù)庫(kù)管理員應(yīng)當(dāng)定期找出這些索引,將它們刪除,從而減少索引對(duì)更新操作的影響。

8.最左前綴匹配原則,非常重要的原則。

mysql會(huì)一直向右匹配直到遇到范圍查詢(>、<、between、like)就停止匹配,比如a 1=”” and=”” b=”2” c=”“> 3 and d = 4 如果建立(a,b,c,d)順序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引則都可以用到,a,b,d的順序可以任意調(diào)整。

9.=和in可以亂序。

比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意順序,mysql的查詢優(yōu)化器會(huì)幫你優(yōu)化成索引可以識(shí)別的形式

10.盡量選擇區(qū)分度高的列作為索引。

區(qū)分度的公式是count(distinct col)/count(*),表示字段不重復(fù)的比例,比例越大我們掃描的記錄數(shù)越少,唯一鍵的區(qū)分度是1,而一些狀態(tài)、性別字段可能在大數(shù)據(jù)面前區(qū)分度就 是0,那可能有人會(huì)問(wèn),這個(gè)比例有什么經(jīng)驗(yàn)值嗎?使用場(chǎng)景不同,這個(gè)值也很難確定,一般需要join的字段我們都要求是0.1以上,即平均1條掃描10條 記錄

11.索引列不能參與計(jì)算,保持列“干凈”。

比如from_unixtime(create_time) = ’2014-05-29’就不能使用到索引,原因很簡(jiǎn)單,b+樹(shù)中存的都是數(shù)據(jù)表中的字段值,但進(jìn)行檢索時(shí),需要把所有元素都應(yīng)用函數(shù)才能比較,顯然成本 太大。所以語(yǔ)句應(yīng)該寫(xiě)成create_time = unix_timestamp(’2014-05-29’);

12.盡量的擴(kuò)展索引,不要新建索引。

比如表中已經(jīng)有a的索引,現(xiàn)在要加(a,b)的索引,那么只需要修改原來(lái)的索引即可

注意:選擇索引的最終目的是為了使查詢的速度變快。上面給出的原則是最基本的準(zhǔn)則,但不能拘泥于上面的準(zhǔn)則。讀者要在以后的學(xué)習(xí)和工作中進(jìn)行不斷的實(shí)踐。根據(jù)應(yīng)用的實(shí)際情況進(jìn)行分析和判斷,選擇最合適的索引方式。

Java中一共有4種引用類型(其實(shí)還有一些其他的引用類型比如FinalReference):強(qiáng)引用、軟引用、弱引用、虛引用。

其中強(qiáng)引用就是我們經(jīng)常使用的Object a = new Object(); 這樣的形式,在Java中并沒(méi)有對(duì)應(yīng)的Reference類。

本篇文章主要是分析軟引用、弱引用、虛引用的實(shí)現(xiàn),這三種引用類型都是繼承于Reference這個(gè)類,主要邏輯也在Reference中。

問(wèn)題

在分析前,先拋幾個(gè)問(wèn)題?

  1. 網(wǎng)上大多數(shù)文章對(duì)于軟引用的介紹是:在內(nèi)存不足的時(shí)候才會(huì)被回收,那內(nèi)存不足是怎么定義的?什么才叫內(nèi)存不足?
  2. 網(wǎng)上大多數(shù)文章對(duì)于虛引用的介紹是:形同虛設(shè),虛引用并不會(huì)決定對(duì)象的生命周期。主要用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。真的是這樣嗎?
  3. 虛引用在Jdk中有哪些場(chǎng)景下用到了呢?

Reference

我們先看下Reference.java中的幾個(gè)字段

  1. public abstract class Reference<T> { 
  2.     //引用的對(duì)象 
  3.     private T referent;         
  4.     //回收隊(duì)列,由使用者在Reference的構(gòu)造函數(shù)中指定 
  5.     volatile ReferenceQueue<? super T> queue; 
  6.      //當(dāng)該引用被加入到queue中的時(shí)候,該字段被設(shè)置為queue中的下一個(gè)元素,以形成鏈表結(jié)構(gòu) 
  7.     volatile Reference next
  8.     //在GC時(shí),JVM底層會(huì)維護(hù)一個(gè)叫DiscoveredList的鏈表,存放的是Reference對(duì)象,discovered字段指向的就是鏈表中的下一個(gè)元素,由JVM設(shè)置 
  9.     transient private Reference<T> discovered;   
  10.     //進(jìn)行線程同步的鎖對(duì)象 
  11.     static private class Lock { } 
  12.     private static Lock lock = new Lock(); 
  13.     //等待加入queue的Reference對(duì)象,在GC時(shí)由JVM設(shè)置,會(huì)有一個(gè)java層的線程(ReferenceHandler)源源不斷的從pending中提取元素加入到queue 
  14.     private static Reference<Object> pending = null

一個(gè)Reference對(duì)象的生命周期如下:

主要分為Native層和Java層兩個(gè)部分。

Native層在GC時(shí)將需要被回收的Reference對(duì)象加入到DiscoveredList中(代碼在referenceProcessor.cpp中

process_discovered_references方法),然后將DiscoveredList的元素移動(dòng)到PendingList中(代碼在referenceProcessor.cpp中enqueue_discovered_ref_helper方法),PendingList的隊(duì)首就是Reference類中的pending對(duì)象。

看看Java層的代碼

  1. private static class ReferenceHandler extends Thread { 
  2.          ... 
  3.         public void run() { 
  4.             while (true) { 
  5.                 tryHandlePending(true); 
  6.             } 
  7.         } 
  8.   }  
  9. static boolean tryHandlePending(boolean waitForNotify) { 
  10.         Reference<Object> r; 
  11.         Cleaner c; 
  12.         try { 
  13.             synchronized (lock) { 
  14.                 if (pending != null) { 
  15.                     r = pending; 
  16.                      //如果是Cleaner對(duì)象,則記錄下來(lái),下面做特殊處理 
  17.                     c = r instanceof Cleaner ? (Cleaner) r : null
  18.                     //指向PendingList的下一個(gè)對(duì)象 
  19.                     pending = r.discovered; 
  20.                     r.discovered = null
  21.                 } else { 
  22.                    //如果pending為null就先等待,當(dāng)有對(duì)象加入到PendingList中時(shí),jvm會(huì)執(zhí)行notify 
  23.                     if (waitForNotify) { 
  24.                         lock.wait(); 
  25.                     } 
  26.                     // retry if waited 
  27.                     return waitForNotify; 
  28.                 } 
  29.             } 
  30.         }  
  31.         ... 
  32.  
  33.         // 如果時(shí)CLeaner對(duì)象,則調(diào)用clean方法進(jìn)行資源回收 
  34.         if (c != null) { 
  35.             c.clean(); 
  36.             return true
  37.         } 
  38.         //將Reference加入到ReferenceQueue,開(kāi)發(fā)者可以通過(guò)從ReferenceQueue中poll元素感知到對(duì)象被回收的事件。 
  39.         ReferenceQueue<? super Object> q = r.queue; 
  40.         if (q != ReferenceQueue.NULL) q.enqueue(r); 
  41.         return true
  42.  } 

流程比較簡(jiǎn)單:就是源源不斷的從PendingList中提取出元素,然后將其加入到ReferenceQueue中去,開(kāi)發(fā)者可以通過(guò)從ReferenceQueue中poll元素感知到對(duì)象被回收的事件。

另外需要注意的是,對(duì)于Cleaner類型(繼承自虛引用)的對(duì)象會(huì)有額外的處理:在其指向的對(duì)象被回收時(shí),會(huì)調(diào)用clean方法,該方法主要是用來(lái)做對(duì)應(yīng)的資源回收,在堆外內(nèi)存DirectByteBuffer中就是用Cleaner進(jìn)行堆外內(nèi)存的回收,這也是虛引用在java中的典型應(yīng)用。

看完了Reference的實(shí)現(xiàn),再看看幾個(gè)實(shí)現(xiàn)類里,各自有什么不同。

SoftReference

  1. public class SoftReference<T> extends Reference<T> { 
  2.  
  3.     static private long clock; 
  4.  
  5.     private long timestamp
  6.  
  7.     public SoftReference(T referent) { 
  8.         super(referent); 
  9.         this.timestamp = clock; 
  10.     } 
  11.  
  12.     public SoftReference(T referent, ReferenceQueue<? super T> q) { 
  13.         super(referent, q); 
  14.         this.timestamp = clock; 
  15.     } 
  16.  
  17.     public T get() { 
  18.         T o = super.get(); 
  19.         if (o != null && this.timestamp != clock) 
  20.             this.timestamp = clock; 
  21.         return o; 
  22.     } 
  23.  

軟引用的實(shí)現(xiàn)很簡(jiǎn)單,就多了兩個(gè)字段:clock和timestamp。clock是個(gè)靜態(tài)變量,每次GC時(shí)都會(huì)將該字段設(shè)置成當(dāng)前時(shí)間。timestamp字段則會(huì)在每次調(diào)用get方法時(shí)將其賦值為clock(如果不相等且對(duì)象沒(méi)被回收)。

那這兩個(gè)字段的作用是什么呢?這和軟引用在內(nèi)存不夠的時(shí)候才被回收,又有什么關(guān)系呢?

這些還得看JVM的源碼才行,因?yàn)闆Q定對(duì)象是否需要被回收都是在GC中實(shí)現(xiàn)的。

  1. size_t 
  2. ReferenceProcessor::process_discovered_reflist( 
  3.   DiscoveredList               refs_lists[], 
  4.   ReferencePolicy*             policy, 
  5.   bool                         clear_referent, 
  6.   BoolObjectClosure*           is_alive, 
  7.   OopClosure*                  keep_alive, 
  8.   VoidClosure*                 complete_gc, 
  9.   AbstractRefProcTaskExecutor* task_executor) 
  10.  ... 
  11.    //還記得上文提到過(guò)的DiscoveredList嗎?refs_lists就是DiscoveredList。 
  12.    //對(duì)于DiscoveredList的處理分為幾個(gè)階段,SoftReference的處理就在第一階段 
  13.  ... 
  14.       for (uint i = 0; i < _max_num_q; i++) { 
  15.         process_phase1(refs_lists[i], policy, 
  16.                        is_alive, keep_alive, complete_gc); 
  17.       } 
  18.  ... 
  19.  
  20. //該階段的主要目的就是當(dāng)內(nèi)存足夠時(shí),將對(duì)應(yīng)的SoftReference從refs_list中移除。 
  21. void 
  22. ReferenceProcessor::process_phase1(DiscoveredList&    refs_list, 
  23.                                    ReferencePolicy*   policy, 
  24.                                    BoolObjectClosure* is_alive, 
  25.                                    OopClosure*        keep_alive, 
  26.                                    VoidClosure*       complete_gc) { 
  27.  
  28.   DiscoveredListIterator iter(refs_list, keep_alive, is_alive); 
  29.   // Decide which softly reachable refs should be kept alive. 
  30.   while (iter.has_next()) { 
  31.     iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic() /* allow_null_referent */)); 
  32.     //判斷引用的對(duì)象是否存活 
  33.     bool referent_is_dead = (iter.referent() != NULL) && !iter.is_referent_alive(); 
  34.     //如果引用的對(duì)象已經(jīng)不存活了,則會(huì)去調(diào)用對(duì)應(yīng)的ReferencePolicy判斷該對(duì)象是不時(shí)要被回收 
  35.     if (referent_is_dead && 
  36.         !policy->should_clear_reference(iter.obj(), _soft_ref_timestamp_clock)) { 
  37.       if (TraceReferenceGC) { 
  38.         gclog_or_tty->print_cr("Dropping reference (" INTPTR_FORMAT ": %s"  ") by policy"
  39.                                (void *)iter.obj(), iter.obj()->klass()->internal_name()); 
  40.       } 
  41.       // Remove Reference object from list 
  42.       iter.remove(); 
  43.       // Make the Reference object active again 
  44.       iter.make_active(); 
  45.       // keep the referent around 
  46.       iter.make_referent_alive(); 
  47.       iter.move_to_next(); 
  48.     } else { 
  49.       iter.next(); 
  50.     } 
  51.   } 
  52.  ... 

refs_lists中存放了本次GC發(fā)現(xiàn)的某種引用類型(虛引用、軟引用、弱引用等),而

process_discovered_reflist方法的作用就是將不需要被回收的對(duì)象從refs_lists移除掉,refs_lists最后剩下的元素全是需要被回收的元素,最后會(huì)將其第一個(gè)元素賦值給上文提到過(guò)的Reference.java#pending字段。

ReferencePolicy一共有4種實(shí)現(xiàn):NeverClearPolicy,AlwaysClearPolicy,LRUCurrentHeapPolicy,LRUMaxHeapPolicy。

其中NeverClearPolicy永遠(yuǎn)返回false,代表永遠(yuǎn)不回收SoftReference,在JVM中該類沒(méi)有被使用,AlwaysClearPolicy則永遠(yuǎn)返回true,在referenceProcessor.hpp#setup方法中中可以設(shè)置policy為AlwaysClearPolicy,至于什么時(shí)候會(huì)用到AlwaysClearPolicy,大家有興趣可以自行研究。

LRUCurrentHeapPolicy和LRUMaxHeapPolicy的should_clear_reference方法則是完全相同:

  1. bool LRUMaxHeapPolicy::should_clear_reference(oop p, 
  2.                                              jlong timestamp_clock) { 
  3.   jlong interval = timestamp_clock - java_lang_ref_SoftReference::timestamp(p); 
  4.   assert(interval >= 0, "Sanity check"); 
  5.  
  6.   // The interval will be zero if the ref was accessed since the last scavenge/gc. 
  7.   if(interval <= _max_interval) { 
  8.     return false
  9.   } 
  10.  
  11.   return true

timestamp_clock就是SoftReference的靜態(tài)字段clock,

java_lang_ref_SoftReference::timestamp(p)對(duì)應(yīng)是字段timestamp。如果上次GC后有調(diào)用SoftReference#get,interval值為0,否則為若干次GC之間的時(shí)間差。

_max_interval則代表了一個(gè)臨界值,它的值在LRUCurrentHeapPolicy和LRUMaxHeapPolicy兩種策略中有差異。

  1. void LRUCurrentHeapPolicy::setup() { 
  2.   _max_interval = (Universe::get_heap_free_at_last_gc() / M) * SoftRefLRUPolicyMSPerMB; 
  3.   assert(_max_interval >= 0,"Sanity check"); 
  4.  
  5. void LRUMaxHeapPolicy::setup() { 
  6.   size_t max_heap = MaxHeapSize; 
  7.   max_heap -= Universe::get_heap_used_at_last_gc(); 
  8.   max_heap /= M; 
  9.  
  10.   _max_interval = max_heap * SoftRefLRUPolicyMSPerMB; 
  11.   assert(_max_interval >= 0,"Sanity check"); 

看到這里你就知道SoftReference到底什么時(shí)候被被回收了,它和使用的策略(默認(rèn)應(yīng)該是LRUCurrentHeapPolicy),堆可用大小,該SoftReference上一次調(diào)用get方法的時(shí)間都有關(guān)系。

WeakReference

  1. public class WeakReference<T> extends Reference<T> { 
  2.  
  3.     public WeakReference(T referent) { 
  4.         super(referent); 
  5.     } 
  6.  
  7.     public WeakReference(T referent, ReferenceQueue<? super T> q) { 
  8.         super(referent, q); 
  9.     } 
  10.  

可以看到,對(duì)于Soft references和Weak references clear_referent字段傳入的都是true,這也符合我們的預(yù)期:對(duì)象不可達(dá)后,引用字段就會(huì)被置為null,然后對(duì)象就會(huì)被回收(對(duì)于軟引用來(lái)說(shuō),如果內(nèi)存足夠的話,在Phase 1,相關(guān)的引用就會(huì)從refs_list中被移除,到Phase 3時(shí)refs_list為空集合)。

但對(duì)于Final references和 Phantom references,clear_referent字段傳入的是false,也就意味著被這兩種引用類型引用的對(duì)象,如果沒(méi)有其他額外處理,只要Reference對(duì)象還存活,那引用的對(duì)象是不會(huì)被回收的。Final references和對(duì)象是否重寫(xiě)了finalize方法有關(guān),不在本文分析范圍之內(nèi),我們接下來(lái)看看Phantom references。

可以看到WeakReference在Java層只是繼承了Reference,沒(méi)有做任何的改動(dòng)。那referent字段是什么時(shí)候被置為null的呢?要搞清楚這個(gè)問(wèn)題我們?cè)倏聪律衔奶岬竭^(guò)的

process_discovered_reflist方法:

 

  1. size_t 
  2. ReferenceProcessor::process_discovered_reflist( 
  3.   DiscoveredList               refs_lists[], 
  4.   ReferencePolicy*             policy, 
  5.   bool                         clear_referent, 
  6.   BoolObjectClosure*           is_alive, 
  7.   OopClosure*                  keep_alive, 
  8.   VoidClosure*                 complete_gc, 
  9.   AbstractRefProcTaskExecutor* task_executor) 
  10.  ... 
  11.  
  12.   //Phase 1:將所有不存活但是還不能被回收的軟引用從refs_lists中移除(只有refs_lists為軟引用的時(shí)候,這里policy才不為null) 
  13.   if (policy != NULL) { 
  14.     if (mt_processing) { 
  15.       RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/); 
  16.       task_executor->execute(phase1); 
  17.     } else { 
  18.       for (uint i = 0; i < _max_num_q; i++) { 
  19.         process_phase1(refs_lists[i], policy, 
  20.                        is_alive, keep_alive, complete_gc); 
  21.       } 
  22.     } 
  23.   } else { // policy == NULL 
  24.     assert(refs_lists != _discoveredSoftRefs, 
  25.            "Policy must be specified for soft references."); 
  26.   } 
  27.  
  28.   // Phase 2: 
  29.   // 移除所有指向?qū)ο筮€存活的引用 
  30.   if (mt_processing) { 
  31.     RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/); 
  32.     task_executor->execute(phase2); 
  33.   } else { 
  34.     for (uint i = 0; i < _max_num_q; i++) { 
  35.       process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc); 
  36.     } 
  37.   } 
  38.  
  39.   // Phase 3: 
  40.   // 根據(jù)clear_referent的值決定是否將不存活對(duì)象回收 
  41.   if (mt_processing) { 
  42.     RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/); 
  43.     task_executor->execute(phase3); 
  44.   } else { 
  45.     for (uint i = 0; i < _max_num_q; i++) { 
  46.       process_phase3(refs_lists[i], clear_referent, 
  47.                      is_alive, keep_alive, complete_gc); 
  48.     } 
  49.   } 
  50.  
  51.   return total_list_count; 
  52.  
  53. void 
  54. ReferenceProcessor::process_phase3(DiscoveredList&    refs_list, 
  55.                                    bool               clear_referent, 
  56.                                    BoolObjectClosure* is_alive, 
  57.                                    OopClosure*        keep_alive, 
  58.                                    VoidClosure*       complete_gc) { 
  59.   ResourceMark rm; 
  60.   DiscoveredListIterator iter(refs_list, keep_alive, is_alive); 
  61.   while (iter.has_next()) { 
  62.     iter.update_discovered(); 
  63.     iter.load_ptrs(DEBUG_ONLY(false /* allow_null_referent */)); 
  64.     if (clear_referent) { 
  65.       // NULL out referent pointer 
  66.       //將Reference的referent字段置為null,之后會(huì)被GC回收 
  67.       iter.clear_referent(); 
  68.     } else { 
  69.       // keep the referent around 
  70.       //標(biāo)記引用的對(duì)象為存活,該對(duì)象在這次GC將不會(huì)被回收 
  71.       iter.make_referent_alive(); 
  72.     } 
  73.     ... 
  74.   } 
  75.     ... 

不管是弱引用還是其他引用類型,將字段referent置null的操作都發(fā)生在process_phase3中,而具體行為是由clear_referent的值決定的。而clear_referent的值則和引用類型相關(guān)。

 

  1. ReferenceProcessorStats ReferenceProcessor::process_discovered_references( 
  2.   BoolObjectClosure*           is_alive, 
  3.   OopClosure*                  keep_alive, 
  4.   VoidClosure*                 complete_gc, 
  5.   AbstractRefProcTaskExecutor* task_executor, 
  6.   GCTimer*                     gc_timer) { 
  7.   NOT_PRODUCT(verify_ok_to_handle_reflists()); 
  8.     ... 
  9.   //process_discovered_reflist方法的第3個(gè)字段就是clear_referent 
  10.   // Soft references 
  11.   size_t soft_count = 0; 
  12.   { 
  13.     GCTraceTime tt("SoftReference", trace_time, false, gc_timer); 
  14.     soft_count = 
  15.       process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true
  16.                                  is_alive, keep_alive, complete_gc, task_executor); 
  17.   } 
  18.  
  19.   update_soft_ref_master_clock(); 
  20.  
  21.   // Weak references 
  22.   size_t weak_count = 0; 
  23.   { 
  24.     GCTraceTime tt("WeakReference", trace_time, false, gc_timer); 
  25.     weak_count = 
  26.       process_discovered_reflist(_discoveredWeakRefs, NULLtrue
  27.                                  is_alive, keep_alive, complete_gc, task_executor); 
  28.   } 
  29.  
  30.   // Final references 
  31.   size_t final_count = 0; 
  32.   { 
  33.     GCTraceTime tt("FinalReference", trace_time, false, gc_timer); 
  34.     final_count = 
  35.       process_discovered_reflist(_discoveredFinalRefs, NULLfalse
  36.                                  is_alive, keep_alive, complete_gc, task_executor); 
  37.   } 
  38.  
  39.   // Phantom references 
  40.   size_t phantom_count = 0; 
  41.   { 
  42.     GCTraceTime tt("PhantomReference", trace_time, false, gc_timer); 
  43.     phantom_count = 
  44.       process_discovered_reflist(_discoveredPhantomRefs, NULLfalse
  45.                                  is_alive, keep_alive, complete_gc, task_executor); 
  46.   } 
  47.     ... 

可以看到,對(duì)于Soft references和Weak references clear_referent字段傳入的都是true,這也符合我們的預(yù)期:對(duì)象不可達(dá)后,引用字段就會(huì)被置為null,然后對(duì)象就會(huì)被回收(對(duì)于軟引用來(lái)說(shuō),如果內(nèi)存足夠的話,在Phase 1,相關(guān)的引用就會(huì)從refs_list中被移除,到Phase 3時(shí)refs_list為空集合)。

但對(duì)于Final references和 Phantom references,clear_referent字段傳入的是false,也就意味著被這兩種引用類型引用的對(duì)象,如果沒(méi)有其他額外處理,只要Reference對(duì)象還存活,那引用的對(duì)象是不會(huì)被回收的。Final references和對(duì)象是否重寫(xiě)了finalize方法有關(guān),不在本文分析范圍之內(nèi),我們接下來(lái)看看Phantom references。

PhantomReference

 

  1. public class PhantomReference<T> extends Reference<T> { 
  2.  
  3.     public T get() { 
  4.         return null
  5.     } 
  6.  
  7.     public PhantomReference(T referent, ReferenceQueue<? super T> q) { 
  8.         super(referent, q); 
  9.     } 
  10.  

可以看到虛引用的get方法永遠(yuǎn)返回null,我們看個(gè)demo。

  1. public static void demo() throws InterruptedException { 
  2.         Object obj = new Object(); 
  3.         ReferenceQueue<Object> refQueue =new ReferenceQueue<>(); 
  4.         PhantomReference<Object> phanRef =new PhantomReference<>(obj, refQueue); 
  5.  
  6.         Object objg = phanRef.get(); 
  7.         //這里拿到的是null 
  8.         System.out.println(objg); 
  9.         //讓obj變成垃圾 
  10.         obj=null
  11.         System.gc(); 
  12.         Thread.sleep(3000); 
  13.         //gc后會(huì)將phanRef加入到refQueue中 
  14.         Reference<? extends Object> phanRefP = refQueue.remove(); 
  15.          //這里輸出true 
  16.         System.out.println(phanRefP==phanRef); 
  17.     } 

從以上代碼中可以看到,虛引用能夠在指向?qū)ο蟛豢蛇_(dá)時(shí)得到一個(gè)'通知'(其實(shí)所有繼承References的類都有這個(gè)功能),需要注意的是GC完成后,phanRef.referent依然指向之前創(chuàng)建Object,也就是說(shuō)Object對(duì)象一直沒(méi)被回收!

而造成這一現(xiàn)象的原因在上一小節(jié)末尾已經(jīng)說(shuō)了:對(duì)于Final references和 Phantom references,clear_referent字段傳入的時(shí)false,也就意味著被這兩種引用類型引用的對(duì)象,如果沒(méi)有其他額外處理,在GC中是不會(huì)被回收的。

對(duì)于虛引用來(lái)說(shuō),從refQueue.remove();得到引用對(duì)象后,可以調(diào)用clear方法強(qiáng)行解除引用和對(duì)象之間的關(guān)系,使得對(duì)象下次可以GC時(shí)可以被回收掉。

End

針對(duì)文章開(kāi)頭提出的幾個(gè)問(wèn)題,看完分析,我們已經(jīng)能給出回答:

1.我們經(jīng)常在網(wǎng)上看到軟引用的介紹是:在內(nèi)存不足的時(shí)候才會(huì)回收,那內(nèi)存不足是怎么定義的?為什么才叫內(nèi)存不足?

軟引用會(huì)在內(nèi)存不足時(shí)被回收,內(nèi)存不足的定義和該引用對(duì)象get的時(shí)間以及當(dāng)前堆可用內(nèi)存大小都有關(guān)系,計(jì)算公式在上文中也已經(jīng)給出。

2.網(wǎng)上對(duì)于虛引用的介紹是:形同虛設(shè),與其他幾種引用都不同,虛引用并不會(huì)決定對(duì)象的生命周期。主要用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng)。真的是這樣嗎?

嚴(yán)格的說(shuō),虛引用是會(huì)影響對(duì)象生命周期的,如果不做任何處理,只要虛引用不被回收,那其引用的對(duì)象永遠(yuǎn)不會(huì)被回收。所以一般來(lái)說(shuō),從ReferenceQueue中獲得PhantomReference對(duì)象后,如果PhantomReference對(duì)象不會(huì)被回收的話(比如被其他GC ROOT可達(dá)的對(duì)象引用),需要調(diào)用clear方法解除PhantomReference和其引用對(duì)象的引用關(guān)系。

3.虛引用在Jdk中有哪些場(chǎng)景下用到了呢?

DirectByteBuffer中是用虛引用的子類Cleaner.java來(lái)實(shí)現(xiàn)堆外內(nèi)存回收的,后續(xù)會(huì)寫(xiě)篇文章來(lái)說(shuō)說(shuō)堆外內(nèi)存的里里外外。

 

責(zé)任編輯:未麗燕 來(lái)源: 今日頭條
相關(guān)推薦

2018-02-01 09:26:12

面試算法題程序員

2019-03-06 14:26:31

Javascript面試前端

2019-02-21 10:49:51

Redis持久化恢復(fù)

2019-12-16 15:37:57

JavaScript人生第一份工作瀏覽器

2019-07-16 10:10:46

JavaScript數(shù)據(jù)類型

2022-10-09 07:33:38

JavaSPI程序

2009-09-11 11:09:36

C#引用類型

2022-08-12 09:35:36

JavaScript面試

2020-05-14 08:13:56

JDK命令Java

2019-05-15 16:45:13

SpringBoot面試題Java

2017-11-29 14:41:48

神經(jīng)網(wǎng)絡(luò)遞歸神經(jīng)網(wǎng)絡(luò)RNN

2024-06-28 09:07:19

2020-07-01 17:25:28

Redis數(shù)據(jù)庫(kù)內(nèi)存

2010-04-06 13:07:45

Oracle數(shù)據(jù)庫(kù)

2009-09-11 11:17:04

C#引用類型

2009-03-06 16:48:23

數(shù)據(jù)塊原理Oracle

2009-03-26 10:33:34

Oracle數(shù)據(jù)塊數(shù)據(jù)庫(kù)

2022-04-01 12:40:13

MySQL數(shù)據(jù)庫(kù)

2022-09-05 22:22:00

Stream操作對(duì)象

2010-09-17 15:32:52

JVM工作原理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美www视频| 亚洲男同性恋视频| 国产97在线观看| 国产欧美小视频| 成人豆花视频| 午夜av一区二区| 亚洲v欧美v另类v综合v日韩v| 国产又大又粗又长| 亚洲久久一区| 日韩性xxxx爱| 奇米777第四色| 懂色aⅴ精品一区二区三区| 亚洲欧美一区二区三区久本道91| 国语精品中文字幕| 一级黄色短视频| 亚洲欧美卡通另类91av| 久久色精品视频| 粉嫩av懂色av蜜臀av分享| 亚洲我射av| 欧美视频中文字幕在线| 亚洲精品少妇一区二区| 狠狠色伊人亚洲综合网站l| 国产美女精品人人做人人爽 | 播金莲一级淫片aaaaaaa| 亚洲福利影视| 欧洲亚洲国产日韩| 欧美视频在线观看网站| 国产黄色在线网站| 国产精品素人视频| 久久久水蜜桃| 亚洲福利在线观看视频| 美女国产一区二区| 国产成人福利视频| 日韩三级小视频| 欧美99在线视频观看| 自拍偷拍亚洲区| 亚洲午夜久久久久久久国产| 群体交乱之放荡娇妻一区二区| 欧美一区二区三区在线看 | 国产乱人伦偷精品视频免下载| 日本高清+成人网在线观看| 国产在线观看免费av| 91精品国产乱码久久久久久| 中文字幕亚洲欧美在线| 久久精品无码一区| 国产中文精品久高清在线不| 精品伊人久久97| 中文字幕一区二区人妻在线不卡| 国产精品自在| 亚洲国产精品网站| 亚洲天堂2024| 日韩av字幕| 日韩精品在线看| 成人无码www在线看免费| 国产精品美女在线观看直播| 亚洲第五色综合网| 国产精品久久久久久亚洲av| 久久精品论坛| 亚洲激情小视频| 三级黄色片网站| 久久综合色占| 中文字幕精品久久久久| 中国美女黄色一级片| 久久精品国产68国产精品亚洲| 国产亚洲欧美另类中文| 在线视频第一页| 日韩在线第七页| 久久久精品国产| 青娱乐91视频| 99精品免费视频| 日本电影亚洲天堂| 中文字幕有码视频| 国产乱码精品一区二区三区忘忧草 | 这里只有精品免费视频| 男人的天堂久久精品| 国产免费一区二区三区在线观看| 一级特黄aaa大片| 国产麻豆欧美日韩一区| 国产伦精品一区二区三区视频孕妇| 日韩一级在线播放| 中文字幕成人网| 看全色黄大色大片| 国产在线精彩视频| 欧美在线短视频| 在线观看av免费观看| 国产毛片久久久| 国产偷亚洲偷欧美偷精品| 少妇太紧太爽又黄又硬又爽小说| 中文字幕一区二区三区久久网站| 91国产视频在线播放| 少妇一级淫片日本| 国产精品亚洲视频| 久久久国产精品一区二区三区| 岛国大片在线观看| 亚洲精品日产精品乱码不卡| 国产极品在线视频| a∨色狠狠一区二区三区| 欧美精品一卡二卡| 无码一区二区精品| 亚洲精品久久| 国产成人精品久久| 亚洲a视频在线| 欧美国产国产综合| 99色这里只有精品| 四虎精品在线观看| 亚洲国产日韩一区| 国产91在线播放九色| 精品动漫av| 91精品国产综合久久香蕉最新版 | 日韩私人影院| 亚洲女同ⅹxx女同tv| 日韩一级片播放| 国产成人澳门| 久久电影一区二区| 在线免费一区二区| 99视频精品在线| 成人国产在线看| 日韩一区二区三免费高清在线观看| 亚洲成人精品视频在线观看| 在线免费看av网站| 免费观看在线色综合| 精品国产乱码久久久久软件| av在线app| 欧美三级电影网| 在线免费观看黄色小视频| 国产综合欧美| 亚洲已满18点击进入在线看片| 成人免费视频| 一本大道久久a久久综合| 国产视频精品视频| 欧美在线免费| 18成人在线| 久热国产在线| 欧美妇女性影城| 国产在线免费av| 免费成人在线网站| 台湾成人av| 成人黄色图片网站| 国产亚洲精品久久久久久牛牛| 日本一区二区三区精品| 成人禁用看黄a在线| 少妇大叫太大太粗太爽了a片小说| 自拍偷拍亚洲| 久久久91精品国产一区不卡| 91国内精品久久久| 欧美激情一区二区三区在线| 色诱视频在线观看| 精品国产精品国产偷麻豆| 国产成人亚洲综合91精品| 国产天堂素人系列在线视频| 色狠狠综合天天综合综合| 午夜精产品一区二区在线观看的| 美女精品在线观看| 日本一区二区三区免费看| 日韩经典一区| 色噜噜国产精品视频一区二区 | 成人一区二区三区中文字幕| 免费的一级黄色片| 国产精品久久久久久久久久白浆| 97视频在线观看网址| 亚洲 美腿 欧美 偷拍| 欧美视频在线观看免费| 国产三级黄色片| 蜜臀av一区二区在线观看| 特级黄色录像片| 91精品久久久久久综合五月天| 国外视频精品毛片| 囯产精品久久久久久| 激情懂色av一区av二区av| 男生草女生视频| 精油按摩中文字幕久久| 国产精品一二三在线观看| ady日本映画久久精品一区二区| 久久久久久网站| 邻居大乳一区二区三区| 欧美日韩亚洲综合一区 | 欧美视频在线观看免费网址| 久久久视频6r| 国产一区二区精品久久99| 精品少妇在线视频| 国内精品久久久久久久影视简单| 91精品国产自产在线| 国精一区二区三区| 亚洲天堂免费观看| 国产绿帽一区二区三区| 午夜成人免费电影| 国产在线免费av| zzijzzij亚洲日本少妇熟睡| 国产高清视频网站| 亚洲视频碰碰| 亚洲欧美国产一区二区| 中文在线综合| 国产精品美女www爽爽爽视频| av片在线观看| 亚洲丝袜一区在线| 亚洲高清精品视频| 欧美三级一区二区| 欧美成人aaaaⅴ片在线看| 国产精品丝袜久久久久久app| 久久久久无码国产精品一区李宗瑞| 老鸭窝毛片一区二区三区| 在线观看污视频| 大胆日韩av| 精品国产第一页| 高清不卡一区| 国产精品吹潮在线观看| free性欧美| 久久久精品免费| 国产黄在线看| 亚洲国产精品久久久久秋霞不卡| 一级片免费观看视频| 欧美日韩国产页| 婷婷色中文字幕| 国产精品情趣视频| 国产特黄级aaaaa片免| 国产白丝网站精品污在线入口| 五月婷婷丁香色| 毛片一区二区| 男人揉女人奶房视频60分 | 综合亚洲色图| 成人黄色在线免费观看| 国产福利亚洲| 日本在线观看天堂男亚洲 | 中文字幕午夜精品一区二区三区| 日韩欧美三级一区二区| 天海翼亚洲一区二区三区| 91成人在线看| 欧美黄色一级| 91亚洲永久免费精品| 伦一区二区三区中文字幕v亚洲| 热99精品只有里视频精品| 多野结衣av一区| 久久免费精品日本久久中文字幕| 国产欧美黑人| 久久人人爽亚洲精品天堂| 大地资源中文在线观看免费版 | 大地资源网3页在线观看| 国产一区二区三区在线看 | 成人黄色av网址| 亚洲最大的网站| 日本一区二区三区电影免费观看 | 中文久久久久久| 日韩精品乱码av一区二区| 99色精品视频| 手机精品视频在线观看| 日本爱爱免费视频| 日韩精品一二区| 伊人网在线综合| 久草热8精品视频在线观看| www.se五月| 国产经典欧美精品| 中国特级黄色片| 成人午夜免费av| 性久久久久久久久久久| 91啪亚洲精品| av黄色在线免费观看| 欧美国产精品v| 久久视频一区二区三区| 国产精品精品国产色婷婷| 久久人妻无码aⅴ毛片a片app| 亚洲男女一区二区三区| 久久综合激情网| 狠狠躁18三区二区一区| 亚洲黄网在线观看| 欧美精品v国产精品v日韩精品 | 成人精品一区二区三区中文字幕| 亚洲一区二区三区四区av| 91香蕉视频黄| 日韩免费成人av| 亚洲人成网站在线| 九九热精彩视频| 欧美性猛交xxxx富婆弯腰| 中文字幕91爱爱| 欧美一区二区三区四区久久 | 最近日韩中文字幕中文| av香蕉成人| 国产91精品不卡视频| 国产极品嫩模在线观看91精品| 亚洲sss综合天堂久久| 日韩超碰人人爽人人做人人添| 日韩在线三级| 欧美精品导航| 黄色一级大片在线观看| 国产在线播放一区| 亚洲一区二区三区蜜桃| 中文字幕一区二区三| 日本熟妇色xxxxx日本免费看| 日本韩国欧美在线| 成人激情四射网| 亚洲美女在线视频| 丝袜美腿av在线| 青青草一区二区| 日本一区二区三区视频在线看| 欧美动漫一区二区| 欧美在线高清| 亚洲成人福利在线观看| 成人综合激情网| 91禁男男在线观看| 婷婷综合另类小说色区| 国产又粗又黄又爽的视频| 亚洲另类激情图| 中国av在线播放| 国产精品久久久久久久久久小说| 凹凸成人在线| 一区二区三区视频在线播放| a91a精品视频在线观看| 国产精品久久久久久久av福利| 99在线精品免费| 欧美三级 欧美一级| 欧美日韩激情一区| 三级在线电影| 97国产成人精品视频| www一区二区三区| 日韩免费一区二区三区| 国产精品免费看| 中文字幕1区2区| 日韩一区中文字幕| 国产精品传媒在线观看| 亚洲激情在线观看| 国产深夜视频在线观看| 91夜夜未满十八勿入爽爽影院 | 亚洲天堂视频在线| 日韩经典一区二区三区| 青草影视电视剧免费播放在线观看| 91精品久久久久| 成人情趣视频| 日韩一级片播放| 国产欧美一区二区三区在线老狼| 日韩aaaaaa| 亚洲精品第一页| 僵尸再翻生在线观看| 国产在线精品一区二区三区| 韩国在线视频一区| 香蕉视频免费网站| 夜夜精品视频一区二区| 国产成人精品av在线观| 久久精品欧美视频| 色综合久久久| 中文字幕日韩精品久久| 另类小说视频一区二区| 99久久精品久久亚洲精品| 一本到一区二区三区| 蝌蚪视频在线播放| 欧美在线视频导航| 亚洲黄页网站| 国产av无码专区亚洲精品| 久久免费国产精品| 无码人妻精品一区二区| 在线日韩第一页| 久久久久伊人| 国产人妻互换一区二区| 国产成人99久久亚洲综合精品| 精品无码久久久久| 亚洲国产97在线精品一区| 午夜欧美激情| 日本一区二区不卡高清更新| 蜜桃91丨九色丨蝌蚪91桃色| 91久久久久久久久久久久久久| 欧美精品久久久久久久久老牛影院| av观看在线| 国产综合18久久久久久| 久久久噜噜噜久久狠狠50岁| 免费视频91蜜桃| 欧美一级生活片| 爱福利在线视频| 日本一区视频在线观看| 久久精品国产久精国产| 久久午夜无码鲁丝片午夜精品| 亚洲二区中文字幕| 激情开心成人网| 欧美 另类 交| 成人高清视频在线| 精品国产一区二区三区四| www.亚洲成人| 精品素人av| 日韩一区二区三区不卡视频| 亚洲欧美国产三级| 台湾av在线二三区观看| 国产精品三级网站| 国产精品av一区二区| 国产女主播喷水高潮网红在线| 欧美猛男男办公室激情| 菠萝蜜视频在线观看www入口| 欧美lavv| 国产一区二区福利| 中文字幕精品三级久久久| 日韩一区二区三区xxxx| 久久久久观看| 亚洲男人天堂av在线| 午夜久久久久久久久| av午夜在线| 国产一区在线观| 久久99精品久久久久| av大片免费在线观看| 日韩小视频在线| 久久av电影| 亚洲成年人在线观看| 欧美高清激情brazzers| 欧美男女交配| 国产亚洲黄色片|