




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、 可修改 歡迎下載 精品 Word 可修改 歡迎下載 精品 Word 可修改 歡迎下載 精品 WordART運行時Compacting GC為新創(chuàng)立對象分配內存的過程分析在引進Compacting GC后,ART運行時優(yōu)化了堆內存分配過程。最顯著特點是為每個ART運行時線程增加局局部配緩沖區(qū)Thead Local Allocation Buffer和在OOM前進行一次同構空間壓縮Homogeneous Space Compact。前者可提高堆內存分配效率,后者可解決內存碎片問題。本文就對ART運行時引進Compacting GC后的堆內存分配過程進行分析。從接口層面上看,除了提供常規(guī)的對象分配
2、接口AllocObject,ART運行時的堆還提供了一個專門用于分配非移動對象的接口AllocNonMovableObject,如圖1所示:非移動對象指的是保存在前面一篇文章提到的Non-Moving Space的對象,主要包括那些在類加載過程中創(chuàng)立的類對象Class、類方法對象ArtMethod和類成員變量對象ArtField等,以及那些在經(jīng)歷過假設干次Generational Semi-Space GC之后仍然存活的對象。前者是通過AllocNonMovableObject接口分配的,而后者是在執(zhí)行Generational Semi-Space GC過程移動過去的。本文主要關注通過Allo
3、cNonMovableObject接口分配的非移動對象。 無論是通過AllocObject接口分配對象,還是通過AllocNonMovableObject接口分配對象,最后都統(tǒng)一調用了另外一個接口AllocObjectWithAllocator進行具體的分配過程,如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片class Heap public: / Allocates and initializes storage for an object instance. template mirror:Object* AllocObjectThread* se
4、lf, mirror:Class* klass, size_t num_bytes, const PreFenceVisitor& pre_fence_visitor SHARED_LOCKS_REQUIREDLocks:mutator_lock_ return AllocObjectWithAllocatorself, klass, num_bytes, GetCurrentAllocator, pre_fence_visitor; template mirror:Object* AllocNonMovableObjectThread* self, mirror:Class* klass,
5、size_t num_bytes, const PreFenceVisitor& pre_fence_visitor SHARED_LOCKS_REQUIREDLocks:mutator_lock_ return AllocObjectWithAllocatorself, klass, num_bytes, GetCurrentNonMovingAllocator, pre_fence_visitor; template ALWAYS_INLINE mirror:Object* AllocObjectWithAllocator Thread* self, mirror:Class* klass
6、, size_t byte_count, AllocatorType allocator, const PreFenceVisitor& pre_fence_visitor SHARED_LOCKS_REQUIREDLocks:mutator_lock_; AllocatorType GetCurrentAllocator const return current_allocator_; AllocatorType GetCurrentNonMovingAllocator const return current_non_moving_allocator_; private: / Alloca
7、tor type. AllocatorType current_allocator_; const AllocatorType current_non_moving_allocator_; ; 這五個函數(shù)定義在文件art/runtime/gc/heap.h 在Heap類的成員函數(shù)AllocObject和AllocNonMovableObject中,參數(shù)self描述的是當前線程,klass描述的是要分配的對象所屬的類型,參數(shù)num_bytes描述的是要分配的對象的大小,最后一個參數(shù)pre_fence_visitor是一個回調函數(shù),用來在分配對象完成后在當前執(zhí)行路徑中執(zhí)行初始化操作,例如分配完成一
8、個數(shù)組對象,通過該回調函數(shù)立即設置數(shù)組的大小,這樣就可以保證數(shù)組對象的完整性和一致性,防止多線程環(huán)境下通過加鎖來完成相同的操作。 Heap類的成員函數(shù)AllocObjectWithAllocator需要另外一個額外的類型為AllocatorType的參數(shù)來描述分配器的類型,也就是描述要在哪個空間分配對象。AllocatorType是一個枚舉類型,它的定義如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片/ Different types of allocators. enum AllocatorType kAllocatorTypeBumpPointer,
9、 / Use BumpPointer allocator, has entrypoints. kAllocatorTypeTLAB, / Use TLAB allocator, has entrypoints. kAllocatorTypeRosAlloc, / Use RosAlloc allocator, has entrypoints. kAllocatorTypeDlMalloc, / Use dlmalloc allocator, has entrypoints. kAllocatorTypeNonMoving, / Special allocator for non moving
10、objects, doesnt have entrypoints. kAllocatorTypeLOS, / Large object space, also doesnt have entrypoints. ; 這個枚舉類型定義在文件/art/runtime/gc/allocator_type.h。 AllocatorType一共有六個值,它們的含義如下所示: kAllocatorTypeBumpPointer:表示在Bump Pointer Space中分配對象。 kAllocatorTypeTLAB:表示要在由Bump Pointer Space提供的線程局局部配緩沖區(qū)中分配對象。 kA
11、llocatorTypeRosAlloc:表示要在Ros Alloc Space分配對象。 kAllocatorTypeDlMalloc:表示要在Dl Malloc Space分配對象。 kAllocatorTypeNonMoving:表示要在Non Moving Space分配對象。 kAllocatorTypeLOS:表示要在Large Object Space分配對象。 Heap類的成員函數(shù)AllocObject和AllocNonMovableObject使用的分配器類型分別是由成員變量current_allocator_和current_non_moving_allocator_決定的
12、。前者的值與當前使用的GC類型有關。當GC類型發(fā)生變化時,就會調用Heap類的成員函數(shù)ChangeCollector來修改當前使用的GC,同時也會調用另外一個成員函數(shù)ChangeAllocator來修改Heap類的成員變量current_allocator_的值。由于ART運行時只有一個Non-Moving Space,因此后者的值就固定為kAllocatorTypeNonMoving。 Heap類的成員函數(shù)ChangeCollector的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void Heap:ChangeCollectorCollect
13、orType collector_type / TODO: Only do this with all mutators suspended to avoid races. if collector_type != collector_type_ collector_type_ = collector_type; gc_plan_.clear; switch collector_type_ case kCollectorTypeCC: / Fall-through. case kCollectorTypeMC: / Fall-through. case kCollectorTypeSS: /
14、Fall-through. case kCollectorTypeGSS: gc_plan_.push_backcollector:kGcTypeFull; if use_tlab_ ChangeAllocatorkAllocatorTypeTLAB; else ChangeAllocatorkAllocatorTypeBumpPointer; break; case kCollectorTypeMS: gc_plan_.push_backcollector:kGcTypeSticky; gc_plan_.push_backcollector:kGcTypePartial; gc_plan_.
15、push_backcollector:kGcTypeFull; ChangeAllocatorkUseRosAlloc ? kAllocatorTypeRosAlloc : kAllocatorTypeDlMalloc; break; case kCollectorTypeCMS: gc_plan_.push_backcollector:kGcTypeSticky; gc_plan_.push_backcollector:kGcTypePartial; gc_plan_.push_backcollector:kGcTypeFull; ChangeAllocatorkUseRosAlloc ?
16、kAllocatorTypeRosAlloc : kAllocatorTypeDlMalloc; break; default: LOGFATAL Unimplemented; 這個函數(shù)定義在文件ime/gc/heap.cc中。 從這里我們就可以看到,對于Compacting GC,它們使用的分配器類型只可能為kAllocatorTypeTLAB或者kAllocatorTypeBumpPointer,取決定Heap類的成員變量use_tlab_的值。Heap類的成員變量use_tlab_的值默認為false,但是可以通過ART運行時啟動選項-XX:UseTLAB來設置為true。對于Mark-
17、Sweep GC來說,它們使用的分配器類型只可能為kAllocatorTypeRosAlloc或者kAllocatorTypeDlMalloc,取決于常量kUseRosAlloc的值。 此外,我們還可以看到,根據(jù)當前使用的GC不同,Heap類的成員變量gc_plan_會被設置為不同的值,用來表示在分配對象過程中遇到內存缺乏時,應該執(zhí)行的GC粒度。對于Compacting GC來說,只有一種GC粒度可執(zhí)行,那就是kGcTypeFull,實際上就是說對Bump Pointer Space的所有不可達對象進行回收。對于Mark-Sweep GC來說,有三種GC粒度可執(zhí)行,分別是kGcTypeStic
18、ky、kGcTypePartial和kGcTypeFull。這三者的含義可以參考前面一文。后面我們繼續(xù)對象分配過程時,也可以看到Heap類的成員變量gc_plan_的用途。 Heap類的成員函數(shù)ChangeAllocator的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void Heap:ChangeAllocatorAllocatorType allocator if current_allocator_ != allocator current_allocator_ = allocator; MutexLock munullptr, *Loc
19、ks:runtime_shutdown_lock_; SetQuickAllocEntryPointsAllocatorcurrent_allocator_; 這個函數(shù)定義在文件ime/gc/heap.cc中。 Heap類的成員函數(shù)ChangeAllocator除了設置成員變量current_allocator_的值之外,還會調用函數(shù)SetQuickAllocEntryPointsAllocator來修改提供給Native Code的用來分配對象的入口點函數(shù),以便Native Code可以在ART運行時切換GC時使用正常的接口來分配對象。這里所謂的Native Code,就是APK在安裝時通過
20、翻譯DEX字節(jié)碼得到的本地機器指令。 了解了分配器的類型之后,接下來我們就繼續(xù)分析Heap類的成員函數(shù)AllocObjectWithAllocator的實現(xiàn),如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片template inline mirror:Object* Heap:AllocObjectWithAllocatorThread* self, mirror:Class* klass, size_t byte_count, AllocatorType allocator, const PreFenceVisitor& pre_fence_visit
21、or if kCheckLargeObject & UNLIKELYShouldAllocLargeObjectklass, byte_count return AllocLargeObjectself, klass, byte_count, pre_fence_visitor; mirror:Object* obj; if allocator = kAllocatorTypeTLAB byte_count = RoundUpbyte_count, space:BumpPointerSpace:kAlignment; if allocator = kAllocatorTypeTLAB & by
22、te_count TlabSize obj = self-AllocTlabbyte_count; obj-SetClassklass; pre_fence_visitorobj, usable_size; else obj = TryToAllocateself, allocator, byte_count, &bytes_allocated, &usable_size; if UNLIKELYobj = nullptr bool is_current_allocator = allocator = GetCurrentAllocator; obj = AllocateInternalWit
23、hGcself, allocator, byte_count, &bytes_allocated, &usable_size, &klass; if obj = nullptr bool after_is_current_allocator = allocator = GetCurrentAllocator; / If there is a pending exception, fail the allocation right away since the next one / could cause OOM and abort the runtime. if !self-IsExcepti
24、onPending & is_current_allocator & !after_is_current_allocator / If the allocator changed, we need to restart the allocation. return AllocObjectself, klass, byte_count, pre_fence_visitor; return nullptr; obj-SetClassklass; pre_fence_visitorobj, usable_size; if AllocatorHasAllocationStackallocator Pu
25、shOnAllocationStackself, &obj; if AllocatorMayHaveConcurrentGCallocator & IsGcConcurrent CheckConcurrentGCself, new_num_bytes_allocated, &obj; return obj; 這個函數(shù)定義在文件art/runtime/gc/heap-inl.h中。 Heap類的成員函數(shù)AllocObjectWithAllocator分配對象的主要邏輯如圖2所示:首先,如果模板參數(shù)kCheckLargeObject等于true,并且要分配的是一個原子類型數(shù)組,且該為數(shù)組的大小大于
26、預先設置的值,那么忽略掉參數(shù)allocator,而是調用Heap類的另外一個成員函數(shù)AllocLargeObject直接在Large Object Space中分配內存。后一個條件是通過調用Heap類的成員函數(shù)ShouldAllocLargeObject來判斷是否滿足的,它的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片inline bool Heap:ShouldAllocLargeObjectmirror:Class* c, size_t byte_count const / We need to have a zygote space or
27、else our newly allocated large object can end up in the / Zygote resulting in it being prematurely freed. / We can only do this for primitive objects since large objects will not be within the card table / range. This also means that we rely on SetClass not dirtying the objects card. return byte_cou
28、nt = large_object_threshold_ & c-IsPrimitiveArray; 這個函數(shù)定義在文件art/runtime/gc/heap-inl.h中。 Heap類的成員變量large_object_threshold_初始化為kDefaultLargeObjectThreshold,后者又定義為3個內存頁大小。也就是說,當分配的原子類型數(shù)組大小大于等于3個內存頁時,就在Large Object Space中進行分配。 回到Heap類的成員AllocObjectWithAllocator中,如果指定了要在當前ART運行時線程的TLAB中分配對象,并且這時候當前ART運行時
29、線程的TLAB的剩余大小大于請求分配的對象大小,那么就直接在當前線程的TLAB中分配。ART運行時線程的TLAB實際上是來自于Bump Pointer Space上的,后面我們就可以看到這一點。 如果上面的條件都不成立,接下來就調用Heap類的成員函數(shù)TryToAllocate來進行分配了。Heap類的成員函數(shù)TryToAllocate會根據(jù)參數(shù)allocator,在指定的Space分配內存,同時會根據(jù)第二個模板參數(shù)來決定是否要在允許的范圍內增加Space的大小限制,以便可以滿足分配要求。這里指定Heap類的成員函數(shù)TryToAllocate的值為false,就表示現(xiàn)在在不增長Space的大小
30、限制的前提下為對象分配內存。 如果Heap類的成員函數(shù)TryToAllocate不能成功分配到指定大小的內存,那么就需要調用Heap類的成員函數(shù)AllocateInternalWithGc來先執(zhí)行必要的GC,再嘗試分配請求的內存了。 如果Heap類的成員函數(shù)AllocateInternalWithGc也不能成功分配到內存,那就說明是分配失敗了。不過有一個例外,那就是ART運行時當前使用分配器類型發(fā)生了變化,這種情況就需要重新調用Heap類的成員函數(shù)AllocObject重啟分配過程。從上面的分析可以知道,當ART運行時當前使用的GC發(fā)生切換時,ART運行時當前使用的分配器類型也會隨著變化,因此
31、這時候重新調用Heap類的成員函數(shù)AllocObject,就可以使用當前的分配器來分配對象。 假設前面成功分配了到指定的內存,接下來還有兩件事情需要做。 第一件事情是調用Heap類的成員函數(shù)AllocatorHasAllocationStack判斷參數(shù)allocator指定的分配器是否與ART運行時的Allocation Stack有關。如果有關的話,那么就需要將剛剛成功分配到的對象通過調用Heap類的成員函數(shù)PushOnAllocationStack壓入到ART運行時的Allocation Stack中,以便以后可以執(zhí)行Sticky GC。關于Sticky GC,可以參考前面一文。 Heap
32、類的成員函數(shù)AllocatorHasAllocationStack的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片class Heap public: static ALWAYS_INLINE bool AllocatorHasAllocationStackAllocatorType allocator_type return allocator_type != kAllocatorTypeBumpPointer & allocator_type != kAllocatorTypeTLAB; ; 這個函數(shù)定義在文件art/runtime/gc/he
33、ap.h中。 前面提到,ART運行時線程的TLAB是來自于Bump Pointer Space的,而Bump Pointer Space是與Compacting GC相關的,Allocation Stack是與Sticky GC相關的,這就意味著Compacting GC不會執(zhí)行Sticky類型的GC。 第二件事情是調用Heap類的成員函數(shù)AllocatorMayHaveConcurrentGC判斷參數(shù)allocator指定的分配器是否與Concurrent GC相關,并且當前使用的GC就是一個Concurrent GC。如果條件都成立的話,就調用Heap類的成員函數(shù)CheckConcurre
34、ntGC檢查是否需要發(fā)起一個Concurrent GC請求。 Heap類的成員函數(shù)AllocatorMayHaveConcurrentGC的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片class Heap public: static ALWAYS_INLINE bool AllocatorMayHaveConcurrentGCAllocatorType allocator_type return AllocatorHasAllocationStackallocator_type; ; 這個函數(shù)定義在文件art/runtime/gc/heap.h
35、中。 Heap類的成員函數(shù)AllocatorMayHaveConcurrentGC的判斷邏輯與上面分析的成員函數(shù)AllocatorHasAllocationStack是一樣的,這就意味著目前提供的Compacting GC都是非Concurrent的。不過以后是會提供具有Concurrent功能的Compacting GC的,稱為Concurrent Copying GC。 以上就是Heap類的成員函數(shù)AllocObjectWithAllocator的實現(xiàn),接下來我們繼續(xù)分析Heap類的成員函數(shù)TryToAllocate和AllocateInternalWithGc的實現(xiàn),以便可以更好地了解A
36、RT運行時分配對象的過程。這也有利用我們后面分析ART運行時的Compacting GC的執(zhí)行過程。 Heap類的成員函數(shù)TryToAllocate的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片template inline mirror:Object* Heap:TryToAllocateThread* self, AllocatorType allocator_type, size_t alloc_size, size_t* bytes_allocated, size_t* usable_size if allocator_type != k
37、AllocatorTypeTLAB & UNLIKELYIsOutOfMemoryOnAllocationallocator_type, alloc_size return nullptr; mirror:Object* ret; switch allocator_type case kAllocatorTypeBumpPointer: DCHECKbump_pointer_space_ != nullptr; alloc_size = RoundUpalloc_size, space:BumpPointerSpace:kAlignment; ret = bump_pointer_space_
38、-AllocNonvirtualalloc_size; if LIKELYret != nullptr *bytes_allocated = alloc_size; *usable_size = alloc_size; break; case kAllocatorTypeRosAlloc: if kInstrumented & UNLIKELYrunning_on_valgrind_ / If running on valgrind, we should be using the instrumented path. ret = rosalloc_space_-Allocself, alloc
39、_size, bytes_allocated, usable_size; else DCHECK!running_on_valgrind_; ret = rosalloc_space_-AllocNonvirtualself, alloc_size, bytes_allocated, usable_size; break; case kAllocatorTypeDlMalloc: if kInstrumented & UNLIKELYrunning_on_valgrind_ / If running on valgrind, we should be using the instrumente
40、d path. ret = dlmalloc_space_-Allocself, alloc_size, bytes_allocated, usable_size; else DCHECK!running_on_valgrind_; ret = dlmalloc_space_-AllocNonvirtualself, alloc_size, bytes_allocated, usable_size; break; case kAllocatorTypeNonMoving: ret = non_moving_space_-Allocself, alloc_size, bytes_allocate
41、d, usable_size; break; case kAllocatorTypeLOS: ret = large_object_space_-Allocself, alloc_size, bytes_allocated, usable_size; / Note that the bump pointer spaces arent necessarily next to / the other continuous spaces like the non-moving alloc space or / the zygote space. DCHECKret = nullptr | large
42、_object_space_-Containsret; break; case kAllocatorTypeTLAB: DCHECK_ALIGNEDalloc_size, space:BumpPointerSpace:kAlignment; if UNLIKELYself-TlabSize alloc_size const size_t new_tlab_size = alloc_size + kDefaultTLABSize; if UNLIKELYIsOutOfMemoryOnAllocationallocator_type, new_tlab_size return nullptr; /
43、 Try allocating a new thread local buffer, if the allocaiton fails the space must be / full so return nullptr. if !bump_pointer_space_-AllocNewTlabself, new_tlab_size return nullptr; *bytes_allocated = new_tlab_size; else *bytes_allocated = 0; / The allocation cant fail. ret = self-AllocTlaballoc_si
44、ze; DCHECKret != nullptr; *usable_size = alloc_size; break; default: LOGFATAL SetTlabstart, start + bytes; return true; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space.cc中。 BumpPointerSpace類的成員函數(shù)AllocNewTlab首先是調用成員函數(shù)RevokeThreadLocalBuffersLocked撤銷當前ART運行時線程的TLAB,因為之前可能給它分配過TLAB,接著再調用成員函數(shù)AllocBlock
45、在Bump Pointer Space中分配一塊由參數(shù)bytes指定的內存塊,并且調用Thread類的成員函數(shù)SetTlab將該內存塊設置為當前ART運行時線程新的TLAB。接下來我們就繼續(xù)分析上述三個函數(shù)的實現(xiàn)。 BumpPointerSpace類的成員函數(shù)RevokeThreadLocalBuffersLocked的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void BumpPointerSpace:RevokeThreadLocalBuffersLockedThread* thread objects_allocated_.FetchAn
46、dAddSequentiallyConsistentthread-GetThreadLocalObjectsAllocated; bytes_allocated_.FetchAndAddSequentiallyConsistentthread-GetThreadLocalBytesAllocated; thread-SetTlabnullptr, nullptr; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space.cc中。 由于ART運行時線程的TLAB只是記錄了它指向的內存塊的起始地址和結束地址,而實際的內存塊是位于Bump Pointer S
47、pace中的,因此這里就是簡單地將在當前ART運行時線程TLAB分配過的對象和內存數(shù)據(jù)匯總到Bump Pointer Space中去即可,這包括在當前ART運行時線程TLAB分配過的對象數(shù)和內存字數(shù)。最后調用Thread類的成員函數(shù)SetTlab將當前ART運行時線程的TLAB清空,就可以完成撤銷工作了。 BumpPointerSpace類的成員函數(shù)AllocBlock的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片byte* BumpPointerSpace:AllocBlocksize_t bytes bytes = RoundUpbytes,
48、 kAlignment; if !num_blocks_ UpdateMainBlock; byte* storage = reinterpret_cast AllocNonvirtualWithoutAccountingbytes + sizeofBlockHeader; if LIKELYstorage != nullptr BlockHeader* header = reinterpret_caststorage; header-size_ = bytes; / Write out the block header. storage += sizeofBlockHeader; +num_
49、blocks_; return storage; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space.cc中。 Bump Pointer Space支持按塊和按對象分配內存的方式。其中,按塊分配的內存主要就是用來作ART運行時線程的TLAB的。分配出來的內存塊有一個額外的BlockHeader,它主要是用來記錄塊的大小。 BumpPointerSpace類的成員變量num_blocks_記錄了Bump Pointer Space已經(jīng)分配了多少塊內存作為當前ART運行時線程的TLAB。當它的值等于0的時候,就意味著還沒有分配過內存塊作為ART運行時線
50、程的TLAB。這時候首先是調用BumpPointerSpace類的成員函數(shù)UpdateMainBlock記錄一下當前已經(jīng)分配的對象占用的內存大小。實際上就是將最開始那塊以對角為單位分配的內存作為Bump Pointer Space的Main Block。這是一個特殊的Block,因為它沒有通過額外的BlockHeader來描述。 BumpPointerSpace類的成員函數(shù)UpdateMainBlock的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void BumpPointerSpace:UpdateMainBlock DCHECK_EQnum
51、_blocks_, 0U; main_block_size_ = Size; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space.cc中。 從這里我們就可以看到,BumpPointerSpace類的成員函數(shù)UpdateMainBlock主要是將Main Block的大小記錄在成員變量main_block_size_中。注意,BumpPointerSpace類的成員函數(shù)Size是從父類ContinuousSpace繼承下來的,它的職責就是返回當前已經(jīng)分配出去的內存總數(shù)。 回到前面BumpPointerSpace類的成員函數(shù)AllocBlock中,接下
52、來就會調用成員函數(shù)AllocNonvirtualWithoutAccounting執(zhí)行分配內存塊的操作,它的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片inline mirror:Object* BumpPointerSpace:AllocNonvirtualWithoutAccountingsize_t num_bytes DCHECKIsAlignednum_bytes; byte* old_end; byte* new_end; do old_end = end_.LoadRelaxed; new_end = old_end + num_b
53、ytes; / If there is no more room in the region, we are out of memory. if UNLIKELYnew_end growth_end_ return nullptr; while !end_ pareExchangeWeakSequentiallyConsistentold_end, new_end; return reinterpret_castold_end; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space-inl.h中。 Bump Pointer Space當前已經(jīng)分配出去
54、的內存記錄在BumpPointerSpace類的成員變量end_中。只要分配大小為num_bytes的內存塊之后,不會超過當前Bump Pointer Space的限制,那么將BumpPointerSpace類的成員變量end_移動到分配的塊內存的末尾即可。這里通過一個while循環(huán)來修改BumpPointerSpace類的成員變量end_,是因為這里采用了一個非加鎖模式的多線程并發(fā)訪問資源方案。 回到BumpPointerSpace類的成員函數(shù)AllocNewTlab中,當成功分配到新的內存塊之后,接下來就可以調用Thread類的成員函數(shù)SetTlab為當前ART運行時線程設置新的TLAB了
55、,它的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片void Thread:SetTlabbyte* start, byte* end DCHECK_LEstart, end; tlsPtr_.thread_local_start = start; tlsPtr_.thread_local_pos = tlsPtr_.thread_local_start; tlsPtr_.thread_local_end = end; tlsPtr_.thread_local_objects = 0; 這個函數(shù)定義在文件/art/runtime/thread.cc
56、中。 Thread類的成員成變量tlsPtr_指向的是一個線程局部儲存。這個線程局總儲存通過一個tls_ptr_sized_values結構體來描述。在這個tls_ptr_sized_values結構體中,成員變量thread_local_start和thread_local_end記錄了TLAB的起始地址和結束地址,另外兩個成員變量thread_local_pos和thread_local_objects分別用來記錄在當前ART運行時線程的TLAB中下一個要分配的對象的起始地址和已經(jīng)在ART運行時線程的TLAB中分配出去的對象的個數(shù)。 至此,我們就分析完成了BumpPointerSpace類
57、的成員函數(shù)AllocNewTlab為當前ART運行時線程分配一塊TLAB的子過程,接下來再看第二個子過程,即Thread類的成員函數(shù)AllocTlab的實現(xiàn),如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片inline mirror:Object* Thread:AllocTlabsize_t bytes DCHECK_GETlabSize, bytes; +tlsPtr_.thread_local_objects; mirror:Object* ret = reinterpret_casttlsPtr_.thread_local_pos; tlsPtr
58、_.thread_local_pos += bytes; return ret; 這個函數(shù)定義在文件/art/runtime/thread-inl.h中。 在當前ART運行時線程的TLAB中分配對象的過程很簡單,主要將用來當前ART運行時線程的線程局部儲存的一個tls_ptr_sized_values結構體的成員變量thread_local_pos向前移動參數(shù)bytes指定的大小,并且將成員變量thread_local_objects增加1即可,同時將原來成員變量thread_local_pos描述的地址值返回給調用者,作為新分配對象的起始地址。 這樣我們就分析完成了在ART運行時線程的TLA
59、B分配對象的過程,接下來我們繼續(xù)分析BumpPointerSpace類的成員函數(shù)AllocNonvirtual的實現(xiàn),以便可以了解在Bump Pointer Space分配一個普通對象的過程,它的實現(xiàn)如下所示:cpp view plain copy 在CODE上查看代碼片派生到我的代碼片inline mirror:Object* BumpPointerSpace:AllocNonvirtualsize_t num_bytes mirror:Object* ret = AllocNonvirtualWithoutAccountingnum_bytes; if ret != null sm136
60、ptr objects_allocated_.FetchAndAddSequentiallyConsistent1; bytes_allocated_.FetchAndAddSequentiallyConsistentnum_bytes; return ret; 這個函數(shù)定義在文件art/runtime/gc/space/bump_pointer_space-inl.h中。 BumpPointerSpace類的成員函數(shù)AllocNonvirtual通過調用我們前面已經(jīng)分析過的成員函數(shù)AllocNonvirtualWithoutAccounting來在Bump Pointer Space中分配一
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025-2030年中國貼劑行業(yè)發(fā)展現(xiàn)狀及前景規(guī)劃研究報告
- 2025-2030年中國稀土冶煉分離市場運行動態(tài)及發(fā)展前景分析報告
- 2025甘肅省安全員考試題庫附答案
- 南京醫(yī)科大學《課程論文寫作與學術規(guī)范》2023-2024學年第二學期期末試卷
- 黔西南民族職業(yè)技術學院《外國建筑史》2023-2024學年第二學期期末試卷
- 青海交通職業(yè)技術學院《傳感檢測技術》2023-2024學年第二學期期末試卷
- 天津商業(yè)大學《學術論文選題與寫作》2023-2024學年第二學期期末試卷
- 湖北大學《財務會計一》2023-2024學年第二學期期末試卷
- 2025上海市建筑安全員考試題庫及答案
- 西藏大學《軟件交互設計》2023-2024學年第二學期期末試卷
- 小學四年級英語教學反思3篇
- DB1509T 0025-2024 肉牛舍設計與建筑技術規(guī)范
- 上海室內裝飾施工合同示范文本2024年
- 2024版2024年《汽車文化》全套教案
- 房地產(chǎn) -中建科工五大類型項目成本指標庫
- 2024小紅書保健品行業(yè)營銷通案
- 未來網(wǎng)絡支撐下的數(shù)字身份體系:產(chǎn)業(yè)和技術發(fā)展趨勢(2024年)定稿版本
- 新《卷煙營銷》理論知識考試題庫(附答案)
- 中考英語688高頻詞大綱詞頻表
- 知識產(chǎn)權保護與跨境執(zhí)法合作
- 肉類食品配送服務投標方案(技術方案)
評論
0/150
提交評論