ART堆內存由若干個space組成,map表中的space的布局如下:
00000000'12c00000-00000000'12e68fff rw- 0 269000 /dev/ashmem/dalvik-main space (deleted) 00000000'12e69000-00000000'22bfffff --- 269000 fd97000 /dev/ashmem/dalvik-main space (deleted) 00000000'32c00000-00000000'32c00fff rw- 0 1000 /dev/ashmem/dalvik-main space 1 (deleted) 00000000'32c01000-00000000'42bfffff --- 1000 ffff000 /dev/ashmem/dalvik-main space 1 (deleted) 00000000'6f064000-00000000'6feb5fff rw- 0 e52000 /data/dalvik-cache/arm64/system@framework@boot.art 00000000'6feb6000-00000000'7232efff r-- 0 2479000 /data/dalvik-cache/arm64/system@framework@boot.oat 00000000'7232f000-00000000'74825fff r-x 2479000 a36000 /data/dalvik-cache/arm64/system@framework@boot.oat 00000000'74826000-00000000'74826fff rw- 4970000 1000 /data/dalvik-cache/arm64/system@framework@boot.oat 00000000'74827000-00000000'749a6fff rw- 0 180000 /dev/ashmem/dalvik-zygote space (deleted) 00000000'749a7000-00000000'749a7fff rw- 0 1000 /dev/ashmem/dalvik-non moving space (deleted) 00000000'749a8000-00000000'749b9fff rw- 1000 12000 /dev/ashmem/dalvik-non moving space (deleted) 00000000'749ba000-00000000'78027fff --- 13000 366e000 /dev/ashmem/dalvik-non moving space (deleted) 00000000'78028000-00000000'78826fff rw- 3681000 7ff000 /dev/ashmem/dalvik-non moving space (deleted) 00000000'78827000-00000000'98826fff rw- 0 20000000 /dev/ashmem/dalvik-free list large object space (deleted)
非等比例圖如下:
如上圖,可分為如下幾種space:main space、image space、zygote space、non moving space、large object space。
這些space是在art::gc::Heap類的構造函數中被創建出來,其調用流程如下:
main()@frameworks/base/cmds/app_process/app_main.cpp android::AndroidRuntime::startVm()@frameworks/base/core/jni/AndroidRuntime.cpp JNI_CreateJavaVM()@art/runtime/java_vm_ext.cc art::Runtime::Create()@art/runtime/runtime.cc art::Runtime::Init()@art/runtime/runtime.cc art::gc::Heap::Heap()@art/runtime/gc/heap.cc
構建space的代碼如下:
Heap::Heap(...) { ... if (!image_file_name.empty()) { std::string error_msg; //加載boot.art和boot.oat,構建image space auto* image_space = space::ImageSpace::Create(image_file_name.c_str(), image_instruction_set, &error_msg); if (image_space != nullptr) { AddSpace(image_space); uint8_t* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd(); requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize); } } bool separate_non_moving_space = is_zygote || support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) || IsMovingGc(background_collector_type_); std::unique_ptr<MemMap> main_mem_map_1; std::unique_ptr<MemMap> main_mem_map_2; uint8_t* request_begin = requested_alloc_space_begin; if (separate_non_moving_space) { const char* space_name = is_zygote ? kZygoteSpaceName: kNonMovingSpaceName; //zygote space的map,起始地址緊挨着boot.oat,大小為64M non_moving_space_mem_map.reset(MemMap::MapAnonymous(space_name, requested_alloc_space_begin, non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false, &error_str)); request_begin = reinterpret_cast<uint8_t*>(300 * MB); } if (foreground_collector_type_ != kCollectorTypeCC) { if (separate_non_moving_space) { // main space 1的map main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_/*512M*/, &error_str)); } } if (support_homogeneous_space_compaction || background_collector_type_ == kCollectorTypeSS ||foreground_collector_type_ == kCollectorTypeSS) { //main space 2的map main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(), capacity_, &error_str)); } if (separate_non_moving_space) { const size_t size = non_moving_space_mem_map->Size(); // 構建zygote space non_moving_space_ = space::DlMallocSpace::CreateFromMemMap(non_moving_space_mem_map.release(), "zygote / non moving space", kDefaultStartingSize, initial_size, size, size, false); non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity()); AddSpace(non_moving_space_); } if (foreground_collector_type_ == kCollectorTypeCC) { ... } else if (IsMovingGc(foreground_collector_type_) && foreground_collector_type_ != kCollectorTypeGSS) { } else { //構建main space 1 CreateMainMallocSpace(main_mem_map_1.release(), initial_size/*2M*/, growth_limit_/*256M*/, capacity_/*512M*/); AddSpace(main_space_); if (foreground_collector_type_ == kCollectorTypeGSS) { ... } else if (main_mem_map_2.get() != nullptr) { const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1]; //構建main space 2 main_space_backup_.reset(CreateMallocSpaceFromMemMap(main_mem_map_2.release(), initial_size, growth_limit_, capacity_, name, true)); AddSpace(main_space_backup_.get()); } } //構建large object space if (large_object_space_type == space::LargeObjectSpaceType::kFreeList) { large_object_space_ = space::FreeListSpace::Create("free list large object space", nullptr, capacity_); } ... if (large_object_space_ != nullptr) { AddSpace(large_object_space_); } }
【image space】
根據boot.art這個內存鏡像文件創建的space,映射地址是boot.art里指定的。
這塊有系統的java類,其內存不會被釋放,所以也不需要有堆管理模塊。加載image space的同時會加載boot.oat文件。
【main space】
從300M的地址也就是0x12c00000開始的大小為512M的內存區域,絕大部分的object都利用這段空間。它的堆管理模塊是RocAlloc。
有一個相同大小的備用main space區域,暫時不清楚其用途。
【zygote(non moving) space】
緊挨着boot.oat的內存區域,大小為64M,zygote啟動時是以non moving space的形式存在,
主要用於non moving的object:主要是non moving的class或者從其他non moving區域里拷貝出來的對象,比如image space就是non moving區域。
它的堆棧管理塊是Dlmalloc。
【large object space】
緊挨着non moving spage的區域,申請大於等於12k的基本類型或者string類型的數組時會用到這部分內存,
根據配置可分為FreeListSpace和LargeObjectMapSpace。
其中LargeObjectMapSpace是次alloc和free都會調用系統的mmap和munmap,管理模塊邏輯簡單,但效率低。
FreeListSpace會一次性mmap一塊512M內存,用一個相對復雜點的(相對於RocAlloc和Dlmalloc簡單的多)邏輯管理這塊內存,效率高比LargeObjectMapSpace高。
一般系統默認用FreeListSpace作為large object space。
在虛擬機初始化完成前,也就是fork第一個進程(system server)前,調用art::gc::Heap::PreZygoteFork()函數進行一次調整,其調用棧為:
main()@frameworks/base/cmds/app_process/app_main.cpp com.android.internal.os.ZygoteInit.main()@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java com.android.internal.os.ZygoteInit.startSystemServer@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java com.android.internal.os.Zygote.forkSystemServer()@frameworks/base/core/java/com/android/internal/os/Zygote.java dalvik.system.ZygoteHooks.preFork()@libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java dalvik.system.ZygoteHooks.nativePreFork()@libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java art::ZygoteHooks_nativePreFork()@art/runtime/native/dalvik_system_ZygoteHooks.cc art::Runtime::PreZygoteFork()@art/runtime/runtime.cc art::gc::Heap::PreZygoteFork()@art/runtime/gc/heap.cc
調整的目的是將虛擬機初始化階段生成的main space和non moving space里的對象,合並成一塊兒內存,
這部分內存之在虛擬機初始化完成后不會被改變,將他們統一成一個區域,可以共享給所有zygote fork出來的進程,既節省內存,也方便gc管理。
void Heap::PreZygoteFork() { ... if (kCompactZygote) { ... ZygoteCompactingCollector zygote_collector(this); //找到non_moving_space_中的空閑區域,用於插入man_space_里的對象 zygote_collector.BuildBins(non_moving_space_); ... bool reset_main_space = false; if (IsMovingGc(collector_type_)) { ... } else { zygote_collector.SetFromSpace(main_space_); reset_main_space = true; } zygote_collector.SetToSpace(&target_space); zygote_collector.SetSwapSemiSpaces(false); //將main_space_中的對象插入到non_moving_space_中 zygote_collector.Run(kGcCauseCollectorTransition, false); if (reset_main_space) { //重新構建main space main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE); madvise(main_space_->Begin(), main_space_->Capacity(), MADV_DONTNEED); MemMap* mem_map = main_space_->ReleaseMemMap(); RemoveSpace(main_space_); space::Space* old_main_space = main_space_; CreateMainMallocSpace(mem_map, kDefaultInitialSize, std::min(mem_map->Size(), growth_limit_), mem_map->Size()); delete old_main_space; AddSpace(main_space_); } else { ... } ... non_moving_space_->SetEnd(target_space.End()); non_moving_space_->SetLimit(target_space.Limit()); } ChangeCollector(foreground_collector_type_); space::MallocSpace* old_alloc_space = non_moving_space_; RemoveSpace(old_alloc_space); //原先的non moving space被拆分為zygote space和新non moving space zygote_space_ = old_alloc_space->CreateZygoteSpace(kNonMovingSpaceName, low_memory_mode_, &non_moving_space_); delete old_alloc_space; AddSpace(zygote_space_); non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity()); AddSpace(non_moving_space_); ... }
合並前main_space_的管理模塊是RosAlloc,而non_moving_space_的管理模塊是Dlmalloc。
由於合並后的內存是不會被釋放的,也就不需要管理模塊,所以這種合並是可行的。
space的繼承關系如下: