ART執行時垃圾收集(GC)過程分析
ART執行時與Dalvik虛擬機器一樣,都使用了Mark-Sweep演算法進行垃圾回收,因此它們的垃圾回收流程在總體上是一致的。但是ART執行時對堆的劃分更加細緻,因而在此基礎上實現了更多樣的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的記憶體就越多,並且它們都有各自的使用情景。這樣就可以使得每次執行GC時,可以最大限度地減少應用程式停頓。本文就詳細分析ART執行時的垃圾收集過程。
ART執行時的垃圾收集收集過程如圖1所示:
圖1 ART執行時的GC執行流程
圖1的最上面三個箭頭描述觸發GC的三種情況,左邊的流程圖描述非並行GC的執行過程,右邊的流程圖描述並行GC的執行流程,接下來我們就詳細圖中涉及到的所有細節。在前面ART執行時為新建立物件分配記憶體的過程分析一文中,我們提到了兩種可能會觸發GC的情況。第一種情況是沒有足夠記憶體分配請求的分存時,會呼叫Heap類的成員函式CollectGarbageInternal觸發一個原因為kGcCauseForAlloc的GC。第二種情況下分配出請求的記憶體之後,堆剩下的記憶體超過一定的閥值,就會呼叫Heap類的成員函式RequestConcurrentGC請求執行一個並行GC。
Heap類的成員函式RequestConcurrentGC的實現如下所示:
-
void Heap::RequestConcurrentGC(Thread* self) {
- // Make sure that we can do a concurrent GC.
- Runtime* runtime = Runtime::Current();
- DCHECK(concurrent_gc_);
- if (runtime == NULL || !runtime->IsFinishedStarting() ||
- !runtime->IsConcurrentGcEnabled()) {
- return;
- }
- {
-
MutexLock mu(self, *Locks::runtime_shutdown_lock_);
- if (runtime->IsShuttingDown()) {
- return;
- }
- }
- if (self->IsHandlingStackOverflow()) {
- return;
- }
- // We already have a request pending, no reason to start more until we update
- // concurrent_start_bytes_.
- concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
- JNIEnv* env = self->GetJniEnv();
- DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
- DCHECK(WellKnownClasses::java_lang_Daemons_requestGC != NULL);
- env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
- WellKnownClasses::java_lang_Daemons_requestGC);
- CHECK(!env->ExceptionCheck());
- }
只有滿足以下四個條件,Heap類的成員函式RequestConcurrentGC才會觸發一個並行GC:
1. ART執行時已經啟動完畢。
2. ART執行時支援並行GC。ART執行時預設是支援並行GC的,但是可以通過啟動選項-Xgc來關閉。
3. ART執行時不是正在關閉。
4. 當前執行緒沒有發生棧溢位。
上述4個條件都滿足之後,Heap類的成員函式RequestConcurrentGC就將成員變數concurrent_start_bytes_的值設定為型別size_t的最大值,表示目前正有一個並行GC在等待執行,以阻止觸發另外一個並行GC。
最後,Heap類的成員函式RequestConcurrentGC呼叫Java層的java.lang.Daemons類的靜態成員函式requestGC請求執行一次並行GC。Java層的java.lang.Daemons類在載入的時候,會啟動五個與堆或者GC相關的守護執行緒,如下所示:
- publicfinalclass Daemons {
- ......
- publicstaticvoid start() {
- ReferenceQueueDaemon.INSTANCE.start();
- FinalizerDaemon.INSTANCE.start();
- FinalizerWatchdogDaemon.INSTANCE.start();
- HeapTrimmerDaemon.INSTANCE.start();
- GCDaemon.INSTANCE.start();
- }
- ......
- }
這五個守護執行緒分別是:
1. ReferenceQueueDaemon:引用佇列守護執行緒。我們知道,在建立引用物件的時候,可以關聯一個佇列。當被引用物件引用的物件被GC回收的時候,被引用物件就會被加入到其建立時關聯的佇列去。這個加入佇列的操作就是由ReferenceQueueDaemon守護執行緒來完成的。這樣應用程式就可以知道那些被引用物件引用的物件已經被回收了。
2. FinalizerDaemon:析構守護執行緒。對於重寫了成員函式finalize的物件,它們被GC決定回收時,並沒有馬上被回收,而是被放入到一個佇列中,等待FinalizerDaemon守護執行緒去呼叫它們的成員函式finalize,然後再被回收。
3. FinalizerWatchdogDaemon:析構監護守護執行緒。用來監控FinalizerDaemon執行緒的執行。一旦檢測那些重定了成員函式finalize的物件在執行成員函式finalize時超出一定的時候,那麼就會退出VM。
4. HeapTrimmerDaemon:堆裁剪守護執行緒。用來執行裁剪堆的操作,也就是用來將那些空閒的堆記憶體歸還給系統。
5. GCDaemon:並行GC執行緒。用來執行並行GC。
Java層的java.lang.Daemons類的靜態成員函式requestGC被呼叫時,就會喚醒上述的並行GC執行緒,然後這個並行GC執行緒就會通過JNI呼叫Heap類的成員函式ConcurrentGC,它的實現如下所示:
- void Heap::ConcurrentGC(Thread* self) {
- {
- MutexLock mu(self, *Locks::runtime_shutdown_lock_);
- if (Runtime::Current()->IsShuttingDown()) {
- return;
- }
- }
- // Wait for any GCs currently running to finish.
- if (WaitForConcurrentGcToComplete(self) == collector::kGcTypeNone) {
- CollectGarbageInternal(next_gc_type_, kGcCauseBackground, false);
- }
- }
只要ART執行時當前不是處於正在關閉的狀態,那麼Heap類的成員函式ConcurrentGC就會檢查當前是否正在執行GC。如果是的話,那麼就等待它執行完成,然後再呼叫Heap類的成員函式CollectGarbageInternal觸發一個原因為kGcCauseBackground的GC。否則的話,就直接呼叫Heap類的成員函式CollectGarbageInternal觸發一個原因為kGcCauseBackground的GC。
從這裡就可以看到,無論是觸發GC的原因是kGcCauseForAlloc,還是kGcCauseBackground,最終都是通過呼叫Heap類的成員函式CollectGarbageInternal來執行GC的。此外,還有第三種情況會觸發GC,如下所示:
- void Heap::CollectGarbage(bool clear_soft_references) {
- // Even if we waited for a GC we still need to do another GC since weaks allocated during the
- // last GC will not have necessarily been cleared.
- Thread* self = Thread::Current();
- WaitForConcurrentGcToComplete(self);
- CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references);
- }
當我們呼叫Java層的java.lang.System的靜態成員函式gc時,如果ART執行時支援顯式GC,那麼就它就會通過JNI呼叫Heap類的成員函式CollectGarbageInternal來觸發一個原因為kGcCauseExplicit的GC。ART執行時預設是支援顯式GC的,但是可以通過啟動選項-XX:+DisableExplicitGC來關閉。
從上面的分析就可以看出,ART執行時在三種情況下會觸發GC,這三種情況通過三個列舉kGcCauseForAlloc、kGcCauseBackground和kGcCauseExplicitk來描述。這三人列舉的定義如下所示:
- // What caused the GC?
- enum GcCause {
- // GC triggered by a failed allocation. Thread doing allocation is blocked waiting for GC before
- // retrying allocation.
- kGcCauseForAlloc,
- // A background GC trying to ensure there is free memory ahead of allocations.
- kGcCauseBackground,
- // An explicit System.gc() call.
- kGcCauseExplicit,
- };
從上面的分析還可以看出,ART執行時的所有GC都是以Heap類的成員函式CollectGarbageInternal為入口,它的實現如下所示:
- collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCause gc_cause,
- bool clear_soft_references) {
- Thread* self = Thread::Current();
- ......
- // Ensure there is only one GC at a time.
- bool start_collect = false;
- while (!start_collect) {
- {
- MutexLock mu(self, *gc_complete_lock_);
- if (!is_gc_running_) {
- is_gc_running_ = true;
- start_collect = true;
- }
- }
- if (!start_collect) {
- // TODO: timinglog this.
- WaitForConcurrentGcToComplete(self);
- ......
- }
- }
- ......
- if (gc_type == collector::kGcTypeSticky &&
- alloc_space_->Size() < min_alloc_space_size_for_sticky_gc_) {
- gc_type = collector::kGcTypePartial;
- }
- ......
- collector::MarkSweep* collector = NULL;
- for (const auto& cur_collector : mark_sweep_collectors_) {
- if (cur_collector->IsConcurrent() == concurrent_gc_ && cur_collector->GetGcType() == gc_type) {
- collector = cur_collector;
- break;
- }
- }
- ......
- collector->clear_soft_references_ = clear_soft_references;
- collector->Run();
- ......
- {
- MutexLock mu(self, *gc_complete_lock_);
- is_gc_running_ = false;
- last_gc_type_ = gc_type;
- // Wake anyone who may have been waiting for the GC to complete.
- gc_complete_cond_->Broadcast(self);
-
相關推薦
ART執行時垃圾收集(GC)過程分析
ART執行時與Dalvik虛擬機器一樣,都使用了Mark-Sweep演算法進行垃圾回收,因此它們的垃圾回收流程在總體上是一致的。但是ART執行時對堆的劃分更加細緻,因而在此基礎上實現了更多樣的回收策略。不同的策略有不同的回收力度,力度越大的回收策略,每次回收的記憶
Dalvik虛擬機器垃圾收集(GC)過程分析
前面我們分析了Dalvik虛擬機器堆的建立過程,以及Java物件在堆上的分配過程。這些知識都是理解Dalvik虛擬機器垃圾收集過程的基礎。垃圾收集是一個複雜的過程,它要將那些不再被引用的物件進行回收。一方面要求Dalvik虛擬機器能夠標記出哪些物件是不再被引用的
ART執行時Mark-Compact( MC)GC執行過程分析
除了Semi-Space(SS)GC和Generational Semi-Space(GSS)GC,ART執行時還引入了第三種Compacting GC:Mark-Compact(MC)GC。這三種GC雖然都是Compacting GC,不過它們的實現方式卻有很
Java垃圾回收(GC)機制詳解
nbsp 引用計數 維護 png 對象 最新 新的 com 前沿 垃圾回收算法有兩種,根據不同的虛擬機策略不同 1、引用計數法 2、可達性分析法 由於我們平常使用的hotspot虛擬機用的是第二種。 那哪些是可達的呢? 這個算法的基本思想是通過一系列稱為“GC Roots”
JVM——垃圾回收(GC)
.text 永久代 lines script from nes ng- code addclass GC簡單介紹 java語言執行在java虛擬機(jvm)上。為了解決有限的空間和性能的保證這個矛盾體,jvm所具備的GC能力。能夠有效的清除不用的對象。
JVM (四)--垃圾收集(二)
一、垃圾收集演算法 1、標記-清除 將存活的物件進行標記,然後清除掉未被標記的物件。 不足: 標記和清除過程中效率多不高; 會產生大量不連續的記憶體碎片,導致無法給大物件分配記憶體。 2、標記-整理 讓所有存活的物件都向一端移動,然
執行時型別資訊(RTTI)之遞迴列印類資訊
深度優先 public class ClassPrint { private static void printSupers(Class<?> clazz) { String name = clazz.getCanonicalName(); System.out.p
《自己動手寫java虛擬機器》學習筆記(七)-----執行緒私有執行時資料區(go)
專案地址:https://github.com/gongxianshengjiadexiaohuihui 在執行java程式時,Java虛擬機器需要使用記憶體來存放各種各樣的資料,Java虛擬機器規範把這些記憶體的區
Java虛擬機器 :Java垃圾回收(GC)機制詳解
轉自:http://www.importnew.com/28413.html 哪些記憶體需要回收? 哪些記憶體需要回收是垃圾回收機制第一個要考慮的問題,所謂“要回收的垃圾”無非就是那些不可能再被任何途徑使用的物件。那麼如何找到這些物件? 1、引用計數法 這個演算法的實現是,給物件中新
JVM03------垃圾收集(下)
一. 什麼是GC Java與C語言相比的一個優勢是,可以通過自己的JVM自動分配和回收記憶體空間。 垃圾回收機制是由垃圾收集器Garbage Collection來實現的,GC是後臺一個低優先順序的守護程序。在記憶體中低到一定限度時才會自動執行,因此垃圾回收的時間是不確定的。 為何要這樣設計:因為GC也
Python3 垃圾回收(GC)(一)
1. 小整數物件池 整數在程式中的使用非常廣泛,Python為了優化速度,使用了小整數物件池, 避免為整數頻繁申請和銷燬記憶體空間。 Python 對小整數的定義是 [-5, 257) 這些整數物件是提前建立好的,不會被垃圾回收。在一個 Python 的程式中,所有位於這個範圍內的整數使用
JVM 垃圾回收(GC)機制
目錄 一、背景 二、 哪些記憶體需要回收? 1、引用計數演算法 2 、可達性分析演算法 三、 四種引用狀態 1、強引用 2、軟引用 3、弱引用 4、虛引用 物件死亡(被回收)前的最後一次掙扎 方法區如何判斷是否需要回收 四、垃圾收集
C++11 | 執行時型別識別(RTTI)
type_info類 typeid操作符 type_index類 type_info type_info類在標頭檔案<typeinfo>中定義,代表了一個C++型別的相關資訊。一般由t
Java應用程式執行時監控方法(一)——JVMTI的應用
The JVM Tool Interface (JVMTI) 是一個由JVM提供的用於開發針對Java程式開發與監控工具的程式設計介面,通過JVMTI介面(Native API)可以建立代理程式(Agent)以監視和控制 Java 應用程式,包括剖析、除錯、監控
JAVA虛擬機器之一:垃圾回收(GC)機制
引言 java對於其它語言(c/c++)來說,建立一個物件使用後,不用顯式的delete/free,且能在一定程度上保證系統記憶體資源及時回收,這要功歸於java的自動垃圾回收機制(Garbage Collection,GC),但也是因為自動回收機制存在,一旦系統內洩漏或存
Java中垃圾回收(gc)問題
以下哪項陳述是正確的? A. 垃圾回收執行緒的優先順序很高,以保證不再 使用的記憶體將被及時回收 B. 垃圾收集允許程式開發者明確指定釋放 哪一個物件 C. 垃圾回收機制保證了JAVA程式不會出現 記憶體溢位 D. 進入”Dead”狀態的執行緒將被垃圾回
將執行時地理資料庫(*.geodatabase)複製到檔案地理資料庫
摘要 將執行時地理資料庫的內容複製到新的檔案地理資料庫中。 用法 語法 CopyRuntimeGdbToFileGdb_conversion (in_file, out_file) 引數 說明 資料型別 in_file 執行時地理資料庫將被複制到檔案地理
再論C++之垃圾回收(GC)
原理:基於引用計數(reference count)。 這種垃圾回收(gc)演算法無非都是給每一塊分配的記憶體提供引用計數,然後通過智慧指標(smart pointer)自動完成引用計數的加減,如果引用技術減少到零,就代表沒有人使用該記憶體了,這塊記憶體就可以回收了。如果可以正確的遵從這種gc的使用規則,也就
golang的垃圾回收(GC)機制
然後再到這裡 golang的垃圾回收採用的是標記-清理(Mark-and-Sweep)演算法 就是先標記出需要回收的記憶體物件快,然後在清理掉; 在這裡不介紹標記和清理的具體策略(可以參考htt
託管堆和垃圾回收(GC)
一、基礎 首先,為了深入瞭解垃圾回收(GC),我們要了解一些基礎知識: CLR:Common Language Runtime,即公共語言執行時,是一個可由多種面向CLR的程式語言使用的“執行時”,包括記憶體管理、程式集載入、安全性、異常處理和執行緒同步等核心功能。 託管程序中的兩種記憶體堆: 託管堆:C