【55期】面試中經(jīng)常被問到Java引用類型原理,帶你深入剖析
閱讀本文大概需要 8.5?分鐘。
來自:github.com/farmerjohngit/myblog/issues/10
問題
Reference
public?abstract?class?Reference<T>?{
????//引用的對象
????private?T?referent;????????
????//回收隊列,由使用者在Reference的構(gòu)造函數(shù)中指定
????volatile?ReferenceQueue?super?T>?queue;
?????//當(dāng)該引用被加入到queue中的時候,該字段被設(shè)置為queue中的下一個元素,以形成鏈表結(jié)構(gòu)
????volatile?Reference?next;
????//在GC時,JVM底層會維護一個叫DiscoveredList的鏈表,存放的是Reference對象,discovered字段指向的就是鏈表中的下一個元素,由JVM設(shè)置
????transient?private?Reference?discovered;??
????//進行線程同步的鎖對象
????static?private?class?Lock?{?}
????private?static?Lock?lock?=?new?Lock();
????//等待加入queue的Reference對象,在GC時由JVM設(shè)置,會有一個java層的線程(ReferenceHandler)源源不斷的從pending中提取元素加入到queue
????private?static?Reference

private?static?class?ReferenceHandler?extends?Thread?{
?????????...
????????public?void?run()?{
????????????while?(true)?{
????????????????tryHandlePending(true);
????????????}
????????}
??}?
static?boolean?tryHandlePending(boolean?waitForNotify)?{
????????Reference
public?class?SoftReference<T>?extends?Reference<T>?{
????static?private?long?clock;
????private?long?timestamp;
????public?SoftReference(T?referent)?{
????????super(referent);
????????this.timestamp?=?clock;
????}
????public?SoftReference(T?referent,?ReferenceQueue?super?T>?q)?{
????????super(referent,?q);
????????this.timestamp?=?clock;
????}
????public?T?get()?{
????????T?o?=?super.get();
????????if?(o?!=?null?&&?this.timestamp?!=?clock)
????????????this.timestamp?=?clock;
????????return?o;
????}
}
size_t
ReferenceProcessor::process_discovered_reflist(
??DiscoveredList???????????????refs_lists[],
??ReferencePolicy*?????????????policy,
??bool?????????????????????????clear_referent,
??BoolObjectClosure*???????????is_alive,
??OopClosure*??????????????????keep_alive,
??VoidClosure*?????????????????complete_gc,
??AbstractRefProcTaskExecutor*?task_executor)
{
?...
???//還記得上文提到過的DiscoveredList嗎?refs_lists就是DiscoveredList。
???//對于DiscoveredList的處理分為幾個階段,SoftReference的處理就在第一階段
?...
??????for?(uint?i?=?0;?i?????????process_phase1(refs_lists[i],?policy,
???????????????????????is_alive,?keep_alive,?complete_gc);
??????}
?...
}
//該階段的主要目的就是當(dāng)內(nèi)存足夠時,將對應(yīng)的SoftReference從refs_list中移除。
void
ReferenceProcessor::process_phase1(DiscoveredList&????refs_list,
???????????????????????????????????ReferencePolicy*???policy,
???????????????????????????????????BoolObjectClosure*?is_alive,
???????????????????????????????????OopClosure*????????keep_alive,
???????????????????????????????????VoidClosure*???????complete_gc)?{
??DiscoveredListIterator?iter(refs_list,?keep_alive,?is_alive);
??//?Decide?which?softly?reachable?refs?should?be?kept?alive.
??while?(iter.has_next())?{
????iter.load_ptrs(DEBUG_ONLY(!discovery_is_atomic()?/*?allow_null_referent?*/));
????//判斷引用的對象是否存活
????bool?referent_is_dead?=?(iter.referent()?!=?NULL)?&&?!iter.is_referent_alive();
????//如果引用的對象已經(jīng)不存活了,則會去調(diào)用對應(yīng)的ReferencePolicy判斷該對象是不時要被回收
????if?(referent_is_dead?&&
????????!policy->should_clear_reference(iter.obj(),?_soft_ref_timestamp_clock))?{
??????if?(TraceReferenceGC)?{
????????gclog_or_tty->print_cr("Dropping?reference?("?INTPTR_FORMAT?":?%s"??")?by?policy",
???????????????????????????????(void?*)iter.obj(),?iter.obj()->klass()->internal_name());
??????}
??????//?Remove?Reference?object?from?list
??????iter.remove();
??????//?Make?the?Reference?object?active?again
??????iter.make_active();
??????//?keep?the?referent?around
??????iter.make_referent_alive();
??????iter.move_to_next();
????}?else?{
??????iter.next();
????}
??}
?...
}
ReferencePolicy一共有4種實現(xiàn):NeverClearPolicy,AlwaysClearPolicy,LRUCurrentHeapPolicy,LRUMaxHeapPolicy。
bool?LRUMaxHeapPolicy::should_clear_reference(oop?p,
?????????????????????????????????????????????jlong?timestamp_clock)?{
??jlong?interval?=?timestamp_clock?-?java_lang_ref_SoftReference::timestamp(p);
??assert(interval?>=?0,?"Sanity?check");
??//?The?interval?will?be?zero?if?the?ref?was?accessed?since?the?last?scavenge/gc.
??if(interval?<=?_max_interval)?{
????return?false;
??}
??return?true;
}
void?LRUCurrentHeapPolicy::setup()?{
??_max_interval?=?(Universe::get_heap_free_at_last_gc()?/?M)?*?SoftRefLRUPolicyMSPerMB;
??assert(_max_interval?>=?0,"Sanity?check");
}
void?LRUMaxHeapPolicy::setup()?{
??size_t?max_heap?=?MaxHeapSize;
??max_heap?-=?Universe::get_heap_used_at_last_gc();
??max_heap?/=?M;
??_max_interval?=?max_heap?*?SoftRefLRUPolicyMSPerMB;
??assert(_max_interval?>=?0,"Sanity?check");
}
WeakReference
public?class?WeakReference<T>?extends?Reference<T>?{
????public?WeakReference(T?referent)?{
????????super(referent);
????}
????public?WeakReference(T?referent,?ReferenceQueue?super?T>?q)?{
????????super(referent,?q);
????}
}
size_t
ReferenceProcessor::process_discovered_reflist(
??DiscoveredList???????????????refs_lists[],
??ReferencePolicy*?????????????policy,
??bool?????????????????????????clear_referent,
??BoolObjectClosure*???????????is_alive,
??OopClosure*??????????????????keep_alive,
??VoidClosure*?????????????????complete_gc,
??AbstractRefProcTaskExecutor*?task_executor)
{
?...
??//Phase?1:將所有不存活但是還不能被回收的軟引用從refs_lists中移除(只有refs_lists為軟引用的時候,這里policy才不為null)
??if?(policy?!=?NULL)?{
????if?(mt_processing)?{
??????RefProcPhase1Task?phase1(*this,?refs_lists,?policy,?true?/*marks_oops_alive*/);
??????task_executor->execute(phase1);
????}?else?{
??????for?(uint?i?=?0;?i?????????process_phase1(refs_lists[i],?policy,
???????????????????????is_alive,?keep_alive,?complete_gc);
??????}
????}
??}?else?{?//?policy?==?NULL
????assert(refs_lists?!=?_discoveredSoftRefs,
???????????"Policy?must?be?specified?for?soft?references.");
??}
??//?Phase?2:
??//?移除所有指向?qū)ο筮€存活的引用
??if?(mt_processing)?{
????RefProcPhase2Task?phase2(*this,?refs_lists,?!discovery_is_atomic()?/*marks_oops_alive*/);
????task_executor->execute(phase2);
??}?else?{
????for?(uint?i?=?0;?i???????process_phase2(refs_lists[i],?is_alive,?keep_alive,?complete_gc);
????}
??}
??//?Phase?3:
??//?根據(jù)clear_referent的值決定是否將不存活對象回收
??if?(mt_processing)?{
????RefProcPhase3Task?phase3(*this,?refs_lists,?clear_referent,?true?/*marks_oops_alive*/);
????task_executor->execute(phase3);
??}?else?{
????for?(uint?i?=?0;?i???????process_phase3(refs_lists[i],?clear_referent,
?????????????????????is_alive,?keep_alive,?complete_gc);
????}
??}
??return?total_list_count;
}
void
ReferenceProcessor::process_phase3(DiscoveredList&????refs_list,
???????????????????????????????????bool???????????????clear_referent,
???????????????????????????????????BoolObjectClosure*?is_alive,
???????????????????????????????????OopClosure*????????keep_alive,
???????????????????????????????????VoidClosure*???????complete_gc)?{
??ResourceMark?rm;
??DiscoveredListIterator?iter(refs_list,?keep_alive,?is_alive);
??while?(iter.has_next())?{
????iter.update_discovered();
????iter.load_ptrs(DEBUG_ONLY(false?/*?allow_null_referent?*/));
????if?(clear_referent)?{
??????//?NULL?out?referent?pointer
??????//將Reference的referent字段置為null,之后會被GC回收
??????iter.clear_referent();
????}?else?{
??????//?keep?the?referent?around
??????//標(biāo)記引用的對象為存活,該對象在這次GC將不會被回收
??????iter.make_referent_alive();
????}
????...
??}
????...
}
ReferenceProcessorStats?ReferenceProcessor::process_discovered_references(
??BoolObjectClosure*???????????is_alive,
??OopClosure*??????????????????keep_alive,
??VoidClosure*?????????????????complete_gc,
??AbstractRefProcTaskExecutor*?task_executor,
??GCTimer*?????????????????????gc_timer)?{
??NOT_PRODUCT(verify_ok_to_handle_reflists());
????...
??//process_discovered_reflist方法的第3個字段就是clear_referent
??//?Soft?references
??size_t?soft_count?=?0;
??{
????GCTraceTime?tt("SoftReference",?trace_time,?false,?gc_timer);
????soft_count?=
??????process_discovered_reflist(_discoveredSoftRefs,?_current_soft_ref_policy,?true,
?????????????????????????????????is_alive,?keep_alive,?complete_gc,?task_executor);
??}
??update_soft_ref_master_clock();
??//?Weak?references
??size_t?weak_count?=?0;
??{
????GCTraceTime?tt("WeakReference",?trace_time,?false,?gc_timer);
????weak_count?=
??????process_discovered_reflist(_discoveredWeakRefs,?NULL,?true,
?????????????????????????????????is_alive,?keep_alive,?complete_gc,?task_executor);
??}
??//?Final?references
??size_t?final_count?=?0;
??{
????GCTraceTime?tt("FinalReference",?trace_time,?false,?gc_timer);
????final_count?=
??????process_discovered_reflist(_discoveredFinalRefs,?NULL,?false,
?????????????????????????????????is_alive,?keep_alive,?complete_gc,?task_executor);
??}
??//?Phantom?references
??size_t?phantom_count?=?0;
??{
????GCTraceTime?tt("PhantomReference",?trace_time,?false,?gc_timer);
????phantom_count?=
??????process_discovered_reflist(_discoveredPhantomRefs,?NULL,?false,
?????????????????????????????????is_alive,?keep_alive,?complete_gc,?task_executor);
??}
????...
}
PhantomReference
public?class?PhantomReference<T>?extends?Reference<T>?{
????public?T?get()?{
????????return?null;
????}
????public?PhantomReference(T?referent,?ReferenceQueue?super?T>?q)?{
????????super(referent,?q);
????}
}
?public?static?void?demo()?throws?InterruptedException?{
????????Object?obj?=?new?Object();
????????ReferenceQueue<Object>?refQueue?=new?ReferenceQueue<>();
????????PhantomReference<Object>?phanRef?=new?PhantomReference<>(obj,?refQueue);
????????Object?objg?=?phanRef.get();
????????//這里拿到的是null
????????System.out.println(objg);
????????//讓obj變成垃圾
????????obj=null;
????????System.gc();
????????Thread.sleep(3000);
????????//gc后會將phanRef加入到refQueue中
????????Reference?extends?Object>?phanRefP?=?refQueue.remove();
?????????//這里輸出true
????????System.out.println(phanRefP==phanRef);
????}
End
推薦閱讀:
【54期】Java序列化三連問,是什么?為什么需要?如何實現(xiàn)?
【53期】面試官:談一下數(shù)據(jù)庫分庫分表之后,你是如何解決事務(wù)問題?
微信掃描二維碼,關(guān)注我的公眾號
朕已閱?
評論
圖片
表情

