[原文出處-----------------ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)
與Dalvik虛擬機一樣,ART運行時內部也有一個Java堆,用來分配Java對象。當這些Java對象不再被使用時,ART運行時需要回收它們占用的內存。在前面一文中,我們簡要介紹了ART運行時的垃圾收集機制,從中了解到ART運行時內部使用的Java堆是由四種Space以及各種輔助數據結構共同描述的。為了后面可以更好地分析ART運行時的垃圾收集機制,本文就對它內部使用的Java堆的創建過程進行分析。
ART運行時創建Java堆的過程,實際上就是創建在圖1涉及到的各種數據結構:

圖1 ART運行時堆的基本概念以及組成
從圖1可以看到,ART運行時內部使用的Java堆的主要組成包括Image Space、Zygote Space、Allocation Space和Large Object Space四個Space,兩個Mod Union Table,一個Card Table,兩個Heap Bitmap,兩個Object Map,以及三個Object Stack。這些數據結構的介紹和作用可以參考前面[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)一文,接下來我們主要是分析它們的創建過程。
從前面[Android運行時ART加載OAT文件的過程分析](http://blog.csdn.net/luoshengyang/article/details/39307813)一文可以知道,ART運行時內部使用的堆是在ART運行時初始化過程中創建的,即在Runtime類的成員函數Init中創建的,如下所示:
~~~
bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) {
......
UniquePtr<ParsedOptions> options(ParsedOptions::Create(raw_options, ignore_unrecognized));
......
heap_ = new gc::Heap(options->heap_initial_size_,
options->heap_growth_limit_,
options->heap_min_free_,
options->heap_max_free_,
options->heap_target_utilization_,
options->heap_maximum_size_,
options->image_,
options->is_concurrent_gc_enabled_,
options->parallel_gc_threads_,
options->conc_gc_threads_,
options->low_memory_mode_,
options->long_pause_log_threshold_,
options->long_gc_log_threshold_,
options->ignore_max_footprint_);
......
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
Runtime類的成員函數Init首先是調用ParsedOptions類的靜態成員函數Create解析ART運行時的啟動選項,并且保存在變量options指向的一個ParsedOptions對象的各個成員變量中,與堆相關的各個選項的含義如下所示:
1. options->heap_initial_size_: 堆的初始大小,通過選項-Xms指定。
2. options->heap_growth_limit_: 堆允許增長的上限值,這是堆的一個軟上限值,通過選項-XX:HeapGrowthLimit指定。
3. options->heap_min_free_: 堆的最小空閑值,通過選項-XX:HeapMinFree指定。
4. options->heap_max_free_: 堆的最大空閑值,通過選項-XX:HeapMaxFree指定。
5. options->heap_target_utilization_: 堆的目標利用率,通過選項-XX:HeapTargetUtilization指定。
6. options->heap_maximum_size_: 堆的最大值,這是堆的一個硬上限值,通過選項-Xmx指定。
7. options->image_: 用來創建Image Space的Image文件,通過選項-Ximage指定。
8. options->is_concurrent_gc_enabled_: 是否支持并行GC,通過選項-Xgc指定。
9. options->parallel_gc_threads_: GC暫停階段用于同時執行GC任務的線程數,通過選項-XX:ParallelGCThreads指定。
10. options->conc_gc_threads_: GC非暫停階段用于同時執行GC任務的線程數,通過選項-XX:ConcGCThreads指定。
11. options->low_memory_mode_: 是否在低內存模式運行,通過選項XX:LowMemoryMode指定。
12. options->long_pause_log_threshold_: GC造成應用程序暫停的時間閥值,一旦超過該閥值,則輸出警告日志,通過選項XX:LongPauseLogThreshold指定。
13. options->long_gc_log_threshold_: GC時間閥值,一旦超過該閥值,則輸出警告日志,通過選項-XX:LongGCLogThreshold指定。
14. options->ignore_max_footprint_: 不對堆的大小進行限制標志,通過選項-XX:IgnoreMaxFootprint指定。
在上述14個選項中,除了后面的3個選項,其余的選項在前面[Dalvik虛擬機垃圾收集機制簡要介紹](http://blog.csdn.net/luoshengyang/article/details/41338251)和學習計劃這個系列的文章和[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)這篇文章均有詳細解釋過。
接下來我們就繼續分析Heap類的構造函數,以便可以了解堆的創建過程,如下所示:
~~~
static constexpr bool kGCALotMode = false;
static constexpr size_t kGcAlotInterval = KB;
......
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, size_t capacity, const std::string& original_image_file_name,
bool concurrent_gc, size_t parallel_gc_threads, size_t conc_gc_threads,
bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold,
bool ignore_max_footprint)
: ......,
concurrent_gc_(concurrent_gc),
parallel_gc_threads_(parallel_gc_threads),
conc_gc_threads_(conc_gc_threads),
low_memory_mode_(low_memory_mode),
long_pause_log_threshold_(long_pause_log_threshold),
long_gc_log_threshold_(long_gc_log_threshold),
ignore_max_footprint_(ignore_max_footprint),
......,
capacity_(capacity),
growth_limit_(growth_limit),
max_allowed_footprint_(initial_size),
......,
max_allocation_stack_size_(kGCALotMode ? kGcAlotInterval
: (kDesiredHeapVerification > kNoHeapVerification) ? KB : MB),
......,
min_free_(min_free),
max_free_(max_free),
target_utilization_(target_utilization),
...... {
......
live_bitmap_.reset(new accounting::HeapBitmap(this));
mark_bitmap_.reset(new accounting::HeapBitmap(this));
// Requested begin for the alloc space, to follow the mapped image and oat files
byte* requested_alloc_space_begin = NULL;
std::string image_file_name(original_image_file_name);
if (!image_file_name.empty()) {
space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name);
......
AddContinuousSpace(image_space);
// Oat files referenced by image files immediately follow them in memory, ensure alloc space
// isn't going to get in the middle
byte* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
......
if (oat_file_end_addr > requested_alloc_space_begin) {
requested_alloc_space_begin =
reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(oat_file_end_addr),
kPageSize));
}
}
alloc_space_ = space::DlMallocSpace::Create(Runtime::Current()->IsZygote() ? "zygote space" : "alloc space",
initial_size,
growth_limit, capacity,
requested_alloc_space_begin);
......
alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
AddContinuousSpace(alloc_space_);
// Allocate the large object space.
const bool kUseFreeListSpaceForLOS = false;
if (kUseFreeListSpaceForLOS) {
large_object_space_ = space::FreeListSpace::Create("large object space", NULL, capacity);
} else {
large_object_space_ = space::LargeObjectMapSpace::Create("large object space");
}
......
AddDiscontinuousSpace(large_object_space_);
// Compute heap capacity. Continuous spaces are sorted in order of Begin().
byte* heap_begin = continuous_spaces_.front()->Begin();
size_t heap_capacity = continuous_spaces_.back()->End() - continuous_spaces_.front()->Begin();
if (continuous_spaces_.back()->IsDlMallocSpace()) {
heap_capacity += continuous_spaces_.back()->AsDlMallocSpace()->NonGrowthLimitCapacity();
}
// Allocate the card table.
card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity));
......
image_mod_union_table_.reset(new accounting::ModUnionTableToZygoteAllocspace(this));
......
zygote_mod_union_table_.reset(new accounting::ModUnionTableCardCache(this));
......
// Default mark stack size in bytes.
static const size_t default_mark_stack_size = 64 * KB;
mark_stack_.reset(accounting::ObjectStack::Create("mark stack", default_mark_stack_size));
allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack",
max_allocation_stack_size_));
live_stack_.reset(accounting::ObjectStack::Create("live stack",
max_allocation_stack_size_));
......
if (ignore_max_footprint_) {
SetIdealFootprint(std::numeric_limits<size_t>::max());
concurrent_start_bytes_ = max_allowed_footprint_;
}
// Create our garbage collectors.
for (size_t i = 0; i < 2; ++i) {
const bool concurrent = i != 0;
mark_sweep_collectors_.push_back(new collector::MarkSweep(this, concurrent));
mark_sweep_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
mark_sweep_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
}
......
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
Heap類的構造函數就負責創建上面圖1所示的各種數據結構,創建過程如下所示:
1. 創建Live Bitmap和Mark Bitmap,它們都是使用一個HeapBitmap對象來描述,并且分別保存在成員變量live_bitmap_和mark_bitmap_中。
2. 如果指定了image文件,即參數original_image_file_name的值不等于空,則調用ImageSpace類的靜態成員函數Create創建一個Image Space,并且調用Heap類的成員函數AddContinuousSpace將該Image Space添加到一個在地址空間上連續的Space列表中,即Image Space屬于地址空間連續的Space。在Image文件的頭部,指定了與Image文件關聯的boot.art@classes.oat文件加載到內存的結束位置,我們需要將這個位置取出來,并且將它對齊到頁面大小,保存變量requested_alloc_space_begin中,作為一會要創建的Zygote Space的開始地址。這樣就可以使得Image Space和Zygote Space的布局與圖1所示保持一致。
3. 調用DlMallocSpace類的靜態成員函數Create創建一個Zygote Space,注意最后一個參數requested_alloc_space_begin,指定了Zygote Space的起始地址,它剛剛好是緊跟在boot.art@classes.oat文件的后面。這時候代碼是運行在Zygote進程中,而Zygote進程中的ART運行時剛開始的時候是沒有Zygote Space和Allocation Space之分的。等到Zygote進程fork第一個子進程的時候,才會將這里創建的Zygote Space一分為二,得到一個Zygote Space和一個Allocation Space。這一點與前面[Dalvik虛擬機Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/41581063)一文分析Dalvik虛擬機堆的管理是一樣的。由于這里創建的Zygote Space也是一個地址空間連續的Space,因此它也會被Heap類的成員函數AddContinuousSpace添加一個在地址空間上連續的Space列表中。
4. 接下來是創建Large Object Space。正如前面[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)一文所述,ART運行時提供了兩種Large Object Space,其中一種是Free List實現FreeListSpace,另外一種是由一組相互獨立的內存塊組成的LargeObjectMapSpace。這里由于kUseFreeListSpaceForLOS的值設置為false,因此Large Object Space使用的是后一種實現,通過LargeObjectMapSpace類的靜態成員函數Create來創建。注意,這里創建的Large Object Space屬于地址空間不連續的Space,因此需要調用Heap類的另外一個成員函數AddDiscontinuousSpace將它添加到內部一個在地址空間上不連續的Space列表中。
5. 接下來是計算所有在地址空間上連續的Space占用的內存的大小。此時,地址空間上連續的Space有兩個,分別是Image Space和Zygote Space,它們按照地址從小到大的順序保存在Heap類的成員變量continuous_spaces_描述的一個向量中。由于Image Space的地址小于Zygote Space的地址,因此,保存在Heap類的成員變量continuous_spaces_描述的向量的第一個元素是Image Space,第二個元素是Zygote Space。注意變量heap_capacity的計算,它使用Zygote Space的結束地址減去Image Space的起始地址,得到的大小實際上是包含了圖1所示的boot.art@classes.oat文件映射到內存的大小。此外,變量heap_capacity只是包含了Zygote Space的初始大小,即通過continuous_spaces_.back()->End()得到的大小并沒有真實地反映Zygote Space的真實大小,因此這時候需要獲得Zygote Space的真實大小,并且增加到變量heap_capacity去。首先,continuous_spaces_.back()返回的是一個ContinuousSpace指針,但是它實際上指向的是一個子類DlMallocSpace對象。其次,DlMallocSpace提供了函數NonGrowthLimitCapacity用來獲得真實大小。因此,將continuous_spaces_.back()返回的是一個ContinuousSpace指針轉換為一個DlMallocSpace指針,就可以調用其成員函數NonGrowthLimitCapacity來獲得Zygote Space的真實大小,并且添加到變量heap_capacity中去。從這里我們也可以看到,變量heap_capacity描述的是并不是準確的Image Space和Zygote Space的大小之和,而是一個比它們的和要大的一個值。但是變量heap_capacity是用來創建Card Table的,因此它的值比真實的Space的大小大一些不會影響程序的邏輯正確性。
6. 有了所有在地址空間上連續的Space的大小之和heap_capacity,以及地址最小的Space的起始地址heap_begin之后,就可以調用CardTable類的靜態成員函數Create來創建一個Card Table了。這里的Card Table的創建過程與前面[Dalvik虛擬機Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/41581063)一文分析的Dalvik虛擬機內部使用的Card Table的創建過程是一樣的。從這里我們也可以看出,只有地址空間連續的Space才具有Card Table。
7. 接下來是創建用來記錄在并行GC階段,在Image Space上分配的對象對在Zygote Space和Allocation Space上分配的對象的引用的Mod Union Table,以及在Zygote Space上分配的對象對在Allocation Space上分配的對象的引用的Mod Union Table。前一個Mod Union Table使用ModUnionTableToZygoteAllocspace類來描述,后一個Mod Union Table使用ModUnionTableCardCache類來描述。關于ModUnionTableToZygoteAllocspace和ModUnionTableCardCache的關系和用途可以參考前面[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)一文。
8. 接下來是創建Mark Stack、Allocation Stack和Live Stack,分別保存在成員變量mark_stack_、allocation_stack_和live_stack_中,它們均是使用一個ObjectStack對象來描述。Mark Stack的初始大小設置為default_mark_stack_size,即64KB。Allocation Stack和Live Stack的初始大小設置為max_allocation_stack_size_。max_allocation_stack_size_是Heap類的一個成員變量,它的值在構造函數初始化列表中設置,要么等于1KB,要么等于1MB。取決于kGCALotMode和kDesiredHeapVerification兩個值。如果kGCALotMode的值等于true,那么max_allocation_stack_size_的值就等于kGcAlotInterval,即1KB。否則的話,如果kDesiredHeapVerification的值大于kNoHeapVerification的值,即ART運行時運行在堆驗證模式下,max_allocation_stack_size_的值就等于1KB。否則的話,max_allocation_stack_size_的值就等于1MB。從最上面的代碼可以看到,kGCALotMode的值等于false,因此max_allocation_stack_size_的值取決于kDesiredHeapVerification的值。
kDesiredHeapVerification是一個常量,它的定義如下所示:
~~~
// How we want to sanity check the heap's correctness.
enum HeapVerificationMode {
kHeapVerificationNotPermitted, // Too early in runtime start-up for heap to be verified.
kNoHeapVerification, // Production default.
kVerifyAllFast, // Sanity check all heap accesses with quick(er) tests.
kVerifyAll // Sanity check all heap accesses.
};
static constexpr HeapVerificationMode kDesiredHeapVerification = kNoHeapVerification;
~~~
這個常量定義在文件rt/runtime/gc/heap.h 中。
常量kDesiredHeapVerification定義為kNoHeapVerification,即在GC過程不對堆進行驗證,因此前面max_allocation_stack_size_的值會被設置為1MB,即Allocation Stack和Live Stack的初始大小被設置為1MB。
9. 如果ART運行時啟動時指定了-XX:IgnoreMaxFootprint選項,即Heap類的成員變量ignore_max_footprint_的值等于true,那么就需要調用Heap類的成員函數SetIdealFootprint將Heap類的成員變量max_allowed_footprint_的值設置為size_t類型的最大值,即不對堆的大小進行限制。同時也會將Heap類的成員變量concurrent_start_bytes_設置為成員變量max_allowed_footprint_的值,這意味著不會觸發并行GC。
10. 最后創建垃圾收集器,保存在Heap類的成員變量mark_sweep_collectors_描述的一個向量中。這些垃圾收集器一共有兩組,其中一組用來執行并行GC,另外一組用來執行非并行GC。每一組都包含三個垃圾收集器,它們分別是MarkSweep、PartialMarkSweep和StickyMarkSweep。關于這三種垃圾收集器的關系和作用,可以參考前面[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)一文。
接下來我們就主要分析Image Space、Zygote Space、Allocation Space和Large Object Space的創建過程,其它的數據結構等到后面分析對象的分配過程和垃圾回收過程時再分析。
前面提到,Image Space是通過調用ImageSpace類的靜態成員函數Create來創建的,它的實現如下所示:
~~~
ImageSpace* ImageSpace::Create(const std::string& original_image_file_name) {
if (OS::FileExists(original_image_file_name.c_str())) {
// If the /system file exists, it should be up-to-date, don't try to generate
return space::ImageSpace::Init(original_image_file_name, false);
}
// If the /system file didn't exist, we need to use one from the dalvik-cache.
// If the cache file exists, try to open, but if it fails, regenerate.
// If it does not exist, generate.
std::string image_file_name(GetDalvikCacheFilenameOrDie(original_image_file_name));
if (OS::FileExists(image_file_name.c_str())) {
space::ImageSpace* image_space = space::ImageSpace::Init(image_file_name, true);
if (image_space != NULL) {
return image_space;
}
}
CHECK(GenerateImage(image_file_name)) << "Failed to generate image: " << image_file_name;
return space::ImageSpace::Init(image_file_name, true);
}
~~~
這個函數定義在文件art/runtime/gc/space/image_space.cc中。
ImageSpace類的靜態成員函數Create我們在前面[Android運行時ART加載OAT文件的過程分析](http://blog.csdn.net/luoshengyang/article/details/39307813)一文已經分析過了, 它的執行邏輯如下所示:
1. 判斷參數original_image_file_name指定的Image文件是否存在。如果存在,就調用ImageSpace類的靜態成員函數Init創建一個Image Space。否則的話,繼續往下執行。
2. 判斷/data/dalvik-cache目錄下是否存在一個system@framework@boot.art@classes.dex文件。如果存在,就調用ImageSpace類的靜態成員函數Init創建一個Image Space。否則的話,繼續往下執行。
3. 調用ImageSpace類的靜態成員函數GenerateImage在/data/dalvik-cache目錄創建一個system@framework@boot.art@classes.dex,作為Image文件,并且調用ImageSpace類的靜態成員函數Init創建一個Image Space。
Image文件的創建過程可以參考前面[Android運行時ART加載OAT文件的過程分析](http://blog.csdn.net/luoshengyang/article/details/39307813)一文,這里我們主要分析ImageSpace類的靜態成員函數Init的實現,以便可以了解Image Space的創建過程,如下所示:
~~~
ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_oat_file) {
......
UniquePtr<File> file(OS::OpenFileForReading(image_file_name.c_str()));
......
ImageHeader image_header;
bool success = file->ReadFully(&image_header, sizeof(image_header));
......
// Note: The image header is part of the image due to mmap page alignment required of offset.
UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
image_header.GetImageSize(),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_FIXED,
file->Fd(),
0,
false));
......
UniquePtr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
PROT_READ, MAP_PRIVATE,
file->Fd(), image_header.GetBitmapOffset(),
false));
......
size_t bitmap_index = bitmap_index_.fetch_add(1);
std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name.c_str(),
bitmap_index));
UniquePtr<accounting::SpaceBitmap> bitmap(
accounting::SpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
reinterpret_cast<byte*>(map->Begin()),
map->Size()));
......
Runtime* runtime = Runtime::Current();
mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod);
runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kSaveAll);
callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsOnlySaveMethod);
runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsOnly);
callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
UniquePtr<ImageSpace> space(new ImageSpace(image_file_name, map.release(), bitmap.release()));
......
space->oat_file_.reset(space->OpenOatFile());
......
return space.release();
}
~~~
這個函數定義在文件art/runtime/gc/space/image_space.cc中。
函數首先是調用OS::OpenFileForReading函數打開參數image_file_name指定的Image文件,目的是為了讀取位于文件開始的一個Image文件頭image_header。Image文件頭使用類ImageHeader來描述,它的定義如下所示:
~~~
class PACKED(4) ImageHeader {
......
private:
......
byte magic_[4];
byte version_[4];
// Required base address for mapping the image.
uint32_t image_begin_;
// Image size, not page aligned.
uint32_t image_size_;
// Image bitmap offset in the file.
uint32_t image_bitmap_offset_;
// Size of the image bitmap.
uint32_t image_bitmap_size_;
// Checksum of the oat file we link to for load time sanity check.
uint32_t oat_checksum_;
// Start address for oat file. Will be before oat_data_begin_ for .so files.
uint32_t oat_file_begin_;
// Required oat address expected by image Method::GetCode() pointers.
uint32_t oat_data_begin_;
// End of oat data address range for this image file.
uint32_t oat_data_end_;
// End of oat file address range. will be after oat_data_end_ for
// .so files. Used for positioning a following alloc spaces.
uint32_t oat_file_end_;
// Absolute address of an Object[] of objects needed to reinitialize from an image.
uint32_t image_roots_;
......
};
~~~
這個類定義在文件art/runtime/image.h中。
ImageHeader類的各個成員變量的含義如下所示:
1. magic_: Image文件魔數,固定為'art\n'。
2. version_:Image文件版本號,目前設置為'005\0'。
3. image_begin_: 指定Image Space映射到內存的起始地址。
4. image_size_: Image Space的大小。
5. image_bitmap_offset_: 用來描述Image Space的對象的存活的Bitmap在Image文件的偏移位置。
6. image_bitmap_size_: 用來描述Image Space的對象的存活的Bitmap的大小。
7. oat_checksum_: 與Image文件關聯的boot.art@classes.oat文件的檢驗值。
8. oat_file_begin_: 與Image文件關聯的boot.art@classes.oat文件映射到內存的起始位置。
9. oat_data_begin_: 與Image文件關聯的boot.art@classes.oat文件的OATDATA段映射到內存的起始位置。
10. oat_data_end_: 與Image文件關聯的boot.art@classes.oat文件的OATDATA段映射到內存的結束位置。
11. oat_file_end_: 與Image文件關聯的boot.art@classes.oat文件映射到內存的結束位置。
12. image_roots_: 一個Object對象地址數組地址,這些Object對象就是在Image Space上分配的對象。
上面第7到第11個與OAT文件相關的成員變量的具體含義可以進一步參考前面[Android運行時ART加載OAT文件的過程分析](http://blog.csdn.net/luoshengyang/article/details/39307813)一文。
理解了ImageHeader類的各個成員變量的含義之后,我們就可以知道Image文件頭都包含有哪些信息了。回到ImageSpace類的靜態成員函數Init中,接下來它就調用函數MemMap::MapFileAtAddress根據前面讀出來的Image文件頭的image_begin_和image_size_信息將參數image_file_name指定的Image文件里面的Image Space映射到內存來,并且得到一個MemMap對象map,用來描述映射的內存。
接下來再繼續調用函數MemMap::MapFileAtAddress根據Image文件頭的image_bitmap_size_和image_size_信息將參數image_file_name指定的Image文件里面的Bitmap也映射到內存來,并且得到一個MemMap對象image_map,用來描述映射的內存。注意,Image文件里面的Bitmap剛好是位于Space的后面,因此,在調用函數MemMap::MapFileAtAddress映射參數image_file_name指定的Image文件時,將文件偏移位置指定為image_size_對齊到頁面大小的值,也就是調用image_header描述的ImageHeader對象的成員函數GetBitmapOffset得到的返回值。
有了前面的image_map之后,就可以調用SpaceBitmap類的靜態成員函數CreateFromMemMap來創建一個SpaceBitmap對象bitmap了。這個SpaceBitmap對象bitmap描述的就是Image Space的Live Bitmap。
在Image文件頭的成員變量image_roots_描述的對象數組中,有四個特殊的ArtMethod對象,用來描述四種特殊的ART運行時方法。ART運行時方法是一種用來描述其它ART方法的ART方法。它們具有特殊的用途,如下所示:
1. ImageHeader::kResolutionMethod: 用來描述一個還未進行解析和鏈接的ART方法。
2. ImageHeader::kCalleeSaveMethod: 用來描述一個由被調用者保存的r4-r11、lr和s0-s31寄存器的ART方法,即由被調用者保存非參數使用的通用寄存器以及所有的浮點數寄存器。
3. ImageHeader::kRefsOnlySaveMethod: 用來描述一個由被調用者保存的r5-r8、r10-r11和lr寄存器的ART方法,即由被調用者保存非參數使用的通用寄存器。
4. ImageHeader::kRefsAndArgsSaveMethod: 用來描述一個由被調用者保存的r1-r3、r5-r8、r10-r11和lr寄存器的ART方法,即由被調用者保存參數和非參數使用的通用寄存器。
注意,我們上面描述是針對ARM體系結構的ART方法調用約定的。其中,r0寄存器用來保存當前調用的ART方法,r1-r3寄存器用來傳遞前三個參數,其它參數通過棧來傳遞。棧頂由sp寄存器指定,r4寄存器用來保存一個在GC過程中使用到的線程掛起計數器,r5-r8和r10-r11寄存器用來分配給局部變量使用,r9寄存器用來保存當前調用線程對象,lr寄存器用來保存當前ART方法的返回地址,ip寄存器用來保存當前執行的指令地址。
上面四個特殊的ArtMethod對象從Image Space取出來之后,會通過調用Runtime類的成員函數SetResolutionMethod和SetCalleeSaveMethod保存在用來描述ART運行時的一個Runtime對象的內部,其中,第2、3和4個ArtMethod對象在ART運行時內部對應的類型分別為Runtime::kSaveAll、Runtime::kRefsOnly和Runtime::kRefsAndArgs。
這些ART運行時方法在調用還未進行解析和鏈接的ART方法時就會使用到。它們的具體用法可以參考前面[Android運行時ART執行類方法的過程分析](http://blog.csdn.net/luoshengyang/article/details/40289405)一文。
有了前面用來描述Image Space的MemMap對象map和描述Image Space的對象的存活的SpaceBitmap對象bitmap之后,就可以創建一個Image Space了,如下所示:
~~~
ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map,
accounting::SpaceBitmap* live_bitmap)
: MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
DCHECK(live_bitmap != NULL);
live_bitmap_.reset(live_bitmap);
}
~~~
這個函數定義在文件art/runtime/gc/space/image_space.cc中。
從這里就可以看出:
1. Image Space的回收策略為kGcRetentionPolicyNeverCollect,即永遠不會進行垃圾回收。
2. Image Space是一個在地址空間上連續的Space,因為它是通過父類MemMapSpace來管理Space的。
3. Image Space的對象的存活是通過Space Bitmap來標記的。注意,Image Space不像其它Space一樣,有Live和Mark兩個Bitmap。它們而是共用一個Bitmap,這是由于Image Space永遠不會進行垃圾回收。
再回到ImageSpace類的靜態成員函數Init中,在將前面創建的Image Space返回給調用者之前,還會調用ImageSpace類的成員函數OpenOatFile將與前面創建的Image Space關聯的OAT文件也加載到內存來。OAT文件的加載過程可以參考前面[Android運行時ART加載OAT文件的過程分析](http://blog.csdn.net/luoshengyang/article/details/39307813)一文。
這樣,Image Space就創建完成了。接下來我們繼續分析Zygote Space的創建過程。從前面分析的Heap類構造函數可以知道,Zygote Space是一種DlMallocSpace,通過調用DlMallocSpace類的靜態成員函數Create來創建,它的實現如下所示:
~~~
DlMallocSpace* DlMallocSpace::Create(const std::string& name, size_t initial_size, size_t
growth_limit, size_t capacity, byte* requested_begin) {
......
size_t starting_size = kPageSize;
......
// Page align growth limit and capacity which will be used to manage mmapped storage
growth_limit = RoundUp(growth_limit, kPageSize);
capacity = RoundUp(capacity, kPageSize);
UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), requested_begin, capacity,
PROT_READ | PROT_WRITE));
......
void* mspace = CreateMallocSpace(mem_map->Begin(), starting_size, initial_size);
......
// Protect memory beyond the initial size.
byte* end = mem_map->Begin() + starting_size;
if (capacity - initial_size > 0) {
CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), name);
}
// Everything is set so record in immutable structure and leave
MemMap* mem_map_ptr = mem_map.release();
DlMallocSpace* space;
if (RUNNING_ON_VALGRIND > 0) {
space = new ValgrindDlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end,
growth_limit, initial_size);
} else {
space = new DlMallocSpace(name, mem_map_ptr, mspace, mem_map_ptr->Begin(), end, growth_limit);
}
......
return space;
}
~~~
這個函數定義在文件art/runtime/gc/space/dlmalloc_space.cc中。
DlMallocSpace類的靜態成員函數Create創建的Zygote Space的底層是一塊匿名共享內存,參數name就是用來指定這塊匿名共享內存的名稱的。此外,參數capacity指定的是要創建的匿名共享內存的大小,也就要創建的Zygote Space的大小。另外一個參數requested_begin也是和要創建的匿名共享內存相關的,用來指定在映射到進程地址空間的起始地址。剩下的兩個參數initial_size和growth_limit用來指定要創建的Zygote Space的初始大小和增長上限值。
DlMallocSpace類的靜態成員函數Create首先是調用函數MemMap::MapAnonymous創建一塊匿名共享內存,并且得一個用來描述該匿名共享內存的MemMap對象mem_map,接下來再調用DlMallocSpace類的另外一個成員函數CreateMallocSpace來將前面創建好的匿名共享內存封裝成一個mspace,以便后面可以通過C庫提供的malloc和free等接口來分配和釋放內存。這兩步與前面[Dalvik虛擬機Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/41581063)一文分析的Dalvik虛擬機Zygote堆的創建過程是完全是一樣的。
由于一開始并不是整個Zygote Space都是可以用來分配對象,而是只有參數initial_size指定的開始那一部分才可以分配,因此對于initial_size后面的那一部分內存,需要保護起來,方法是調用系統接口mprotect將后面的這部分內存的標志位設置為PROT_NONE。這意味著initial_size后面的那一部分內存是既不可以讀,也不可以寫的。
最后,判斷宏RUNNING_ON_VALGRIND的值是否大于0。如果大于0,那么DlMallocSpace類的靜態成員函數Create接下來創建的是一個ValgrindDlMallocSpace對象作為Zygote Space。否則的話,DlMallocSpace類的靜態成員函數Create接下來創建的就是一個DlMallocSpace對象作為Zygote Space。ValgrindDlMallocSpace類是從DlMallocSpace類繼承下來的,不過它會重寫Alloc和Free等接口,目的是為了在為對象分配內存時,分配一塊比請求大小大16個字節的內存,并且在將該內存塊的開頭和末尾的8個字節設置為不可訪問。通過這種方法就可以檢測分配出去的內存是否被應用程序非法訪問。這就是我們平時經常聽說的Valgrind內存非法訪問檢測原理。
RUNNING_ON_VALGRIND定義在文件external/valgrind/main/include/valgrind.h中,這里我們假設它的值等于0,因此接下來DlMallocSpace類的靜態成員函數Create就會創建一個DlMallocSpace對象作為Zygote Space。DlMallocSpace對象的創建過程如下所示:
~~~
size_t DlMallocSpace::bitmap_index_ = 0;
DlMallocSpace::DlMallocSpace(const std::string& name, MemMap* mem_map, void* mspace, byte* begin,
byte* end, size_t growth_limit)
: MemMapSpace(name, mem_map, end - begin, kGcRetentionPolicyAlwaysCollect),
recent_free_pos_(0), num_bytes_allocated_(0), num_objects_allocated_(0),
total_bytes_allocated_(0), total_objects_allocated_(0),
lock_("allocation space lock", kAllocSpaceLock), mspace_(mspace),
growth_limit_(growth_limit) {
......
size_t bitmap_index = bitmap_index_++;
......
live_bitmap_.reset(accounting::SpaceBitmap::Create(
StringPrintf("allocspace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
Begin(), Capacity()));
......
mark_bitmap_.reset(accounting::SpaceBitmap::Create(
StringPrintf("allocspace %s mark-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
Begin(), Capacity()));
......
}
~~~
這個函數定義在文件art/runtime/gc/space/dlmalloc_space.cc中。
從這里就可以看出:
1. Zygote Space的回收策略為kGcRetentionPolicyAlwaysCollect,即每次GC都會嘗試對它進行垃圾回收。
2. Zygote Space是一個在地址空間上連續的Space,因為它是通過父類MemMapSpace來管理Space的。
3. Image Space的對象的存活是通過Space Bitmap來標記的,其中一個是Live Bitmap,用來標記上次GC后還存活的對象,另外一個是Mark Bitmap,用來標記當前GC后仍存活的對象。
在前面[Dalvik虛擬機Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/41581063)一篇文章中,我們提到,Dalvik虛擬機最開始只有一個Zygote堆,不過在Zygote進程fork第一個子進程之前,就會將該Zygote堆一分為二,其中一個仍然是Zygote堆,另外一個為Active堆。ART運行時同樣也是這樣做的,只不過它是將Zygote Space一分為二,其中一個仍然是Zygote Space,另外一個為Allocation Space。
Zygote進程每次fork子進程的時候,都會調用Runtime類的成員函數PreZygoteFork,這樣ART運行時就可以決定什么時候將Zygote Space一分為二。Runtime類的成員函數PreZygoteFork的實現如下所示:
~~~
bool Runtime::PreZygoteFork() {
heap_->PreZygoteFork();
return true;
}
~~~
這個函數定義在文件rt/runtime/runtime.cc中。
Runtime類的成員變量heap_指向的是一個Heap對象,該Heap對象描述的便是ART運行時堆。Runtime類的成員函數PreZygoteFork的實現很簡單,它通過調用Heap類的成員函數PreZygoteFork來執行拆分Zygote Space的功能。
Heap類的成員函數PreZygoteFork的實現如下所示:
~~~
void Heap::PreZygoteFork() {
static Mutex zygote_creation_lock_("zygote creation lock", kZygoteCreationLock);
// Do this before acquiring the zygote creation lock so that we don't get lock order violations.
CollectGarbage(false);
Thread* self = Thread::Current();
MutexLock mu(self, zygote_creation_lock_);
// Try to see if we have any Zygote spaces.
if (have_zygote_space_) {
return;
}
......
{
// Flush the alloc stack.
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
FlushAllocStack();
}
// Turns the current alloc space into a Zygote space and obtain the new alloc space composed
// of the remaining available heap memory.
space::DlMallocSpace* zygote_space = alloc_space_;
alloc_space_ = zygote_space->CreateZygoteSpace("alloc space");
alloc_space_->SetFootprintLimit(alloc_space_->Capacity());
// Change the GC retention policy of the zygote space to only collect when full.
zygote_space->SetGcRetentionPolicy(space::kGcRetentionPolicyFullCollect);
AddContinuousSpace(alloc_space_);
have_zygote_space_ = true;
......
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
每次Heap類的成員函數PreZygoteFork被調用時,都會調用成員函數CollectGarbage執行一次垃圾收集,也就是Zygote進程每次fork子進程之前,都執行一次垃圾收集,這樣就可以使得fork出來的子進程有一個緊湊的堆空間。
當Heap類的成員變量have_zygote_space_等于true的時候,就表明Zygote進程里面的Zygote Space已經被劃分過了,因此,這時候Heap類的成員函數PreZygoteFork就可以直接返回了,因為接下來的所有操作都是與劃分Zygote Space相關的。
在劃分Zygote Space之前,先將保存在Allocation Stack里面的對象標記到對應的Space的Live Bitmap去,這是通過調用Heap類的成員函數FlushAllocStack來實現的。對于新分配的對象,ART運行時不像Dalvik虛擬機一樣,馬上就將它們標記對應的Space的Live Bitmap中去,而是將它們記錄在Allocation Stack。這樣做是為了可以執行Sticky Mark Sweep垃圾收集,后面分析ART運行時的垃圾收集過程時就可以看到這一點。
Heap類的成員函數FlushAllocStack的實現如下所示:
~~~
void Heap::FlushAllocStack() {
MarkAllocStack(alloc_space_->GetLiveBitmap(), large_object_space_->GetLiveObjects(),
allocation_stack_.get());
allocation_stack_->Reset();
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
Heap類的成員函數FlushAllocStack首先調用另外一個成員函數MarkAllocStack將保存在Allocation Stack里面的對象標記到對應的Space的Live Bitmap去。注意,這時候Zygote進程只有三個Space,分別是Image Space、Zygote Space和Large Object Space。其中,Image Space是不能用來分配新對象的,因此,保存在Allocation Stack里面的對象要么是在Zygote Space上分配的,要么是Large Object Space上分配的。這時候就只需要將Zygote Space和Large Object Space的Live Bitmap取出來,連同Allocation Stack一起,傳遞給Heap類的成員函數MarkAllocStack,記它進行相應的標記。
一旦Heap類的成員函數MarkAllocStack將保存在Allocation Stack里面的對象都標記到對應的Space的Live Bitmap去之后,Heap類的成員函數FlushAllocStack就可以將Allocation Stack清空了。
Heap類的成員函數MarkAllocStack的實現如下所示:
~~~
void Heap::MarkAllocStack(accounting::SpaceBitmap* bitmap, accounting::SpaceSetMap* large_objects,
accounting::ObjectStack* stack) {
mirror::Object** limit = stack->End();
for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
const mirror::Object* obj = *it;
DCHECK(obj != NULL);
if (LIKELY(bitmap->HasAddress(obj))) {
bitmap->Set(obj);
} else {
large_objects->Set(obj);
}
}
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
Heap類的成員函數MarkAllocStack就是遍歷Allocation Stack里面的每一個對象,并且判斷它是屬于Zygote Space還是Large Object Space。如果是屬于Zygote Space,就將Zygote Space的Live Bitmap對應位設置為1。如果是屬于Large Object Space,就將被遍歷對象添加到Large Object Space的Live Space Set Map去,起到的也是將Large Object Space的Live Bitmap對應設置為1的效果。
回到Heap類的成員函數PreZygoteFork中,將保存在Allocation Stack里面的對象標記到對應的Space的Live Bitmap去之后,接下來就開始劃分Zygote Space了。劃分之前,我們首先明確,Heap類的成員變量alloc_space_指向的實際上就是Zygote Space,但是接下來我們要將它指向Allocation Space,因此就先把Heap類的成員變量alloc_space_保存在本地變量zygote_space中。從Zygote Space劃分出一個Allocation Space的操作是通過調用DlMallocSpace類的成員函數CreateZygoteSpace來實現。DlMallocSpace類的成員函數CreateZygoteSpace返回來的是新劃分出來的Allocation Space,因此這時候就將它保存在Heap類的成員變量alloc_space_中了。
最后,Heap類的成員函數PreZygoteFork還要做一些收尾工作,主要包括:
1. 設置新劃分出來的Allocation Space底層使用的mspace的大小值,即將該mspace的大小設置為Allocation Space的大小,這是通過調用DlMallocSpace類的成員函數SetFootprintLimit實現的。
2. 將Zygote Space的回收策略修改為kGcRetentionPolicyFullCollect,這樣只有執行類型為kGcRetentionPolicyFullCollect的GC時,才會對Zygote Space的垃圾進行回收。
3. 調用Heap類的成員函數AddContinuousSpace將新劃分出來的Allocation Space添加到ART運行時內部的Continuous Space列表去。
4. 將Heap類的成員變量have_zygote_space_,表示Zygote Space已經被劃分過了,以后不用再劃分了。
接下來,我們就繼續分析DlMallocSpace類的成員函數CreateZygoteSpace,以便可以了解Zygote Space是如何被一分為二的,它的實現如下所示:
~~~
DlMallocSpace* DlMallocSpace::CreateZygoteSpace(const char* alloc_space_name) {
end_ = reinterpret_cast<byte*>(RoundUp(reinterpret_cast<uintptr_t>(end_), kPageSize));
......
size_t size = RoundUp(Size(), kPageSize);
// Trim the heap so that we minimize the size of the Zygote space.
Trim();
// Trim our mem-map to free unused pages.
GetMemMap()->UnMapAtEnd(end_);
// TODO: Not hardcode these in?
const size_t starting_size = kPageSize;
const size_t initial_size = 2 * MB;
// Remaining size is for the new alloc space.
const size_t growth_limit = growth_limit_ - size;
const size_t capacity = Capacity() - size;
......
SetGrowthLimit(RoundUp(size, kPageSize));
SetFootprintLimit(RoundUp(size, kPageSize));
......
UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(alloc_space_name, End(), capacity, PROT_READ | PROT_WRITE));
void* mspace = CreateMallocSpace(end_, starting_size, initial_size);
// Protect memory beyond the initial size.
byte* end = mem_map->Begin() + starting_size;
if (capacity - initial_size > 0) {
CHECK_MEMORY_CALL(mprotect, (end, capacity - initial_size, PROT_NONE), alloc_space_name);
}
DlMallocSpace* alloc_space =
new DlMallocSpace(alloc_space_name, mem_map.release(), mspace, end_, end, growth_limit);
live_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End()));
......
mark_bitmap_->SetHeapLimit(reinterpret_cast<uintptr_t>(End()));
......
return alloc_space;
}
~~~
這個函數定義在文件runtime/gc/space/dlmalloc_space.cc中。
DlMallocSpace類的成員變量end_是從父類Continuous繼承下來的,描述的是當前Zygote Space使用的最大值,而調用DlMallocSpace類的成員函數Size獲得的是當前Zygote Space使用的大小size。
在前面[Dalvik虛擬機Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/41581063)一篇文章中,我們提到,Dalvik虛擬機在劃分Zygote堆之前,會對Zygote堆底層使用的內存進行裁剪,主要就是將末尾沒有使用到的內存占用的虛擬地址空間和物理頁面歸還給操作系統,以及將中間沒有使用到的內存占用的物理頁面歸還給操作系統。這里在劃分Zygote Space之前,也會執行相同的操作,這些操作通過調用DlMallocSpace類的成員函數Trim和MemMap類的成員函數UnMapAtEnd來實現的。
對Zygote Space進行裁剪之后,接下來就計算新的Allocation Space的大小,實際上就是等于原來Zygote Space的總大小減去已經已經使用的大小。原來Zygote Space的總大小可以調用DlMallocSpace類的成員函數Size獲得,而原來Zygote Space已經使用的大小前面已經得到保存在變量size,因此我們很容易就可以計算得到新的Allocation Space的大小為capacity。
前面計算得到的capacity是新的Allocation Space的硬上限,我們還需要給它設置一個增長上限值,即一個軟上限值。DlMallocSpace類的成員變量growth_limit_描述的是原來Zygote Space的增長上限值,用它的值減去原來Zygote Space已經使用的大小size,就可以得到新的Allocation Space的增長上限值。
我們還需要兩個參數。 一個參數是新的Allocation Space的初始大小initial_size,這里設置為2MB。另一個參數是新的Allocation Space底層使用的mspace的初始大小starting_size,這里設置為kPageSize,即一頁大小。
有了上述這些參數之后,就可以調用MemMap類的靜態成員函數MapAnonymous來創建一塊大小等于capacity的匿名共享內存,并且調用DlMallocSpace類的成員函數CreateMallocSpace將該匿名共享內存封裝成一個mspace。注意,新創建的匿名共享內存映射到進程地址空間時,被指定為end_,即緊跟在Zygote Space的后面。
就像前面創建Zygote Space一樣,對于新創建出來的Allocation Space的末尾部分內存,即不在初始大小的那一部分內存,需要調用系統接口mprotect將其標記為不可訪問。
最后,DlMallocSpace類的成員函數CreateZygoteSpace就可以根據前面獲得的信息創建一個DlMallocSpace對象alloc_space來描述新的Allocation Space了,并且該alloc_space返回給調用者。不過,在返回之前,DlMallocSpace類的成員函數CreateZygoteSpace還需要修改重新得到的Zygote Space使用的Live Bitmap和Mark Bitmap的上限值,即它們可以處理的范圍,就等于原來Zygote Space已經使用的大小。
這樣,Zygote Space和Allocation Space創建過程也分析完成了。我們再繼續分析Large Object Space的創建過程。前面提到,Large Object Space是通過LargeObjectMapSpace類的靜態成員函數Create創建的,它的實現如下所示:
~~~
LargeObjectMapSpace* LargeObjectMapSpace::Create(const std::string& name) {
return new LargeObjectMapSpace(name);
}
~~~
這個函數定義在文件art/runtime/gc/space/large_object_space.cc中。
LargeObjectMapSpace類的靜態成員函數Create創建一個LargeObjectMapSpace對象來描述Large Object Space。LargeObjectMapSpace對象的創建過程如下所示:
~~~
LargeObjectSpace::LargeObjectSpace(const std::string& name)
: DiscontinuousSpace(name, kGcRetentionPolicyAlwaysCollect),
num_bytes_allocated_(0), num_objects_allocated_(0), total_bytes_allocated_(0),
total_objects_allocated_(0) {
}
......
LargeObjectMapSpace::LargeObjectMapSpace(const std::string& name)
: LargeObjectSpace(name),
lock_("large object map space lock", kAllocSpaceLock) {}
~~~
這兩個函數定義在文件art/runtime/gc/space/large_object_space.cc中。
從這里就可以看出:
1. LargeObjectMapSpace繼承于LargeObjectSpace。
2. Large Object Space的回收策略為kGcRetentionPolicyAlwaysCollect,即每次GC都會嘗試對它進行垃圾回收。
3. Large Object Space是一個在地址空間上不連續的Space,因為它是通過父類DiscontinuousSpace來管理Space的。
DiscontinuousSpace類有兩個類型為SpaceSetMap的成員變量live_objects_和mark_objects_,如下所示:
~~~
class DiscontinuousSpace : public Space {
public:
......
protected:
......
UniquePtr<accounting::SpaceSetMap> live_objects_;
UniquePtr<accounting::SpaceSetMap> mark_objects_;
private:
......
};
~~~
這個類定義在文件art/runtime/gc/space/space.h中。
這兩個成員變量分別用來描述Large Object Space的Live Bitmap和Mark Bitmap。注意,這里的Bitmap并不是一個真的Bitmap,而是一個Map。這是由于Large Object Space是一個在地址空間上不連續的Space,因此不能用一塊連續的Bitmap來描述它的對象的存活性。
這樣,Large Object Space的創建過程我們也分析完成了。最后,我們還需要分析Heap類的兩個成員函數AddContinuousSpace和AddDiscontinuousSpace。前者用來在ART運行時內部添加一個Continuous Space,即Zygote Space和Allocation Space,而者用來在ART運行時內部添加一個Discontinuous Space,即Large Object Space。
Heap類的成員函數AddContinuousSpace的實現如下所示:
~~~
void Heap::AddContinuousSpace(space::ContinuousSpace* space) {
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
DCHECK(space != NULL);
DCHECK(space->GetLiveBitmap() != NULL);
live_bitmap_->AddContinuousSpaceBitmap(space->GetLiveBitmap());
DCHECK(space->GetMarkBitmap() != NULL);
mark_bitmap_->AddContinuousSpaceBitmap(space->GetMarkBitmap());
continuous_spaces_.push_back(space);
if (space->IsDlMallocSpace() && !space->IsLargeObjectSpace()) {
alloc_space_ = space->AsDlMallocSpace();
}
// Ensure that spaces remain sorted in increasing order of start address (required for CMS finger)
std::sort(continuous_spaces_.begin(), continuous_spaces_.end(),
[](const space::ContinuousSpace* a, const space::ContinuousSpace* b) {
return a->Begin() < b->Begin();
});
// Ensure that ImageSpaces < ZygoteSpaces < AllocSpaces so that we can do address based checks to
// avoid redundant marking.
bool seen_zygote = false, seen_alloc = false;
for (const auto& space : continuous_spaces_) {
if (space->IsImageSpace()) {
DCHECK(!seen_zygote);
DCHECK(!seen_alloc);
} else if (space->IsZygoteSpace()) {
DCHECK(!seen_alloc);
seen_zygote = true;
} else if (space->IsDlMallocSpace()) {
seen_alloc = true;
}
}
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
Heap類有兩個成員變量live_bitmap_和mark_bitmap_,它們的類型為HeapBitmap。但它們其實并不是一個真正的Bitmap,而是一個Bitmap容器,分別用來保存ART運行時內部所有Continuous Space和Discontinuous Space的Live Bitmap和Mark Bitmap。其中,Continuous Space的Bitmap是一個SpaceBitmap,而Discontinuous Space的Bitmap是一個SpaceSetMap。
Heap類的成員函數AddContinuousSpace首先是將要添加的Continuous Space的Live Bitmap和Mark Bitmap分別添加到成員變量live_bitmap_和mark_bitmap_描述的HeapBitmap去,接著再將要添加的Continuous Space添加到成員變量continuous_spaces_描述的一個向量中去,最后還會對保存在成員變量continuous_spaces_描述的向量的Continuous Space進行排序,以確保它們是按照地址從小到大的順序的排序的,即按照Image Space < Zygote Space < Allocation Space的順序進行排序,就如圖1所示。
Heap類的成員函數AddDiscontinuousSpace的實現如下所示:
~~~
void Heap::AddDiscontinuousSpace(space::DiscontinuousSpace* space) {
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
DCHECK(space != NULL);
DCHECK(space->GetLiveObjects() != NULL);
live_bitmap_->AddDiscontinuousObjectSet(space->GetLiveObjects());
DCHECK(space->GetMarkObjects() != NULL);
mark_bitmap_->AddDiscontinuousObjectSet(space->GetMarkObjects());
discontinuous_spaces_.push_back(space);
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
Heap類的成員函數AddContinuousSpace首先是將要添加的Discontinuous Space的Live Bitmap和Mark Bitmap分別添加到成員變量live_bitmap_和mark_bitmap_描述的HeapBitmap去,接著再將要添加的Discontinuous Space添加到成員變量discontinuous_spaces_描述的一個向量中去。由于Discontinuous Space在地址空間上不能比較大小,因此它們就不像Continuous Space需要排序。
至此,我們就分析完成ART運行時堆的創建過程了,從中我們就可以對ART運行時堆的結構有一個基本的認識。
- 前言
- Android組件設計思想
- Android源代碼開發和調試環境搭建
- Android源代碼下載和編譯
- Android源代碼情景分析法
- Android源代碼調試分析法
- 手把手教你為手機編譯ROM
- 在Ubuntu上下載、編譯和安裝Android最新源代碼
- 在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)
- 如何單獨編譯Android源代碼中的模塊
- 在Ubuntu上為Android系統編寫Linux內核驅動程序
- 在Ubuntu上為Android系統內置C可執行程序測試Linux內核驅動程序
- 在Ubuntu上為Android增加硬件抽象層(HAL)模塊訪問Linux內核驅動程序
- 在Ubuntu為Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口
- 在Ubuntu上為Android系統的Application Frameworks層增加硬件訪問服務
- 在Ubuntu上為Android系統內置Java應用程序測試Application Frameworks層的硬件服務
- Android源代碼倉庫及其管理工具Repo分析
- Android編譯系統簡要介紹和學習計劃
- Android編譯系統環境初始化過程分析
- Android源代碼編譯命令m/mm/mmm/make分析
- Android系統鏡像文件的打包過程分析
- 從CM刷機過程和原理分析Android系統結構
- Android系統架構概述
- Android系統整體架構
- android專用驅動
- Android硬件抽象層HAL
- Android應用程序組件
- Android應用程序框架
- Android用戶界面架構
- Android虛擬機之Dalvik虛擬機
- Android硬件抽象層
- Android硬件抽象層(HAL)概要介紹和學習計劃
- Android專用驅動
- Android Logger驅動系統
- Android日志系統驅動程序Logger源代碼分析
- Android應用程序框架層和系統運行庫層日志系統源代碼分析
- Android日志系統Logcat源代碼簡要分析
- Android Binder驅動系統
- Android進程間通信(IPC)機制Binder簡要介紹和學習計劃
- 淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路
- 淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路
- Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析
- Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析
- Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析
- Android Ashmem驅動系統
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)簡要介紹和學習計劃
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)驅動程序源代碼分析
- Android系統匿名共享內存Ashmem(Anonymous Shared Memory)在進程間共享的原理分析
- Android系統匿名共享內存(Anonymous Shared Memory)C++調用接口分析
- Android應用程序進程管理
- Android應用程序進程啟動過程的源代碼分析
- Android系統進程Zygote啟動過程的源代碼分析
- Android系統默認Home應用程序(Launcher)的啟動過程源代碼分析
- Android應用程序消息機制
- Android應用程序消息處理機制(Looper、Handler)分析
- Android應用程序線程消息循環模型分析
- Android應用程序輸入事件分發和處理機制
- Android應用程序鍵盤(Keyboard)消息處理機制分析
- Android應用程序UI架構
- Android系統的開機畫面顯示過程分析
- Android幀緩沖區(Frame Buffer)硬件抽象層(HAL)模塊Gralloc的實現原理分析
- SurfaceFlinger
- Android系統Surface機制的SurfaceFlinger服務
- SurfaceFlinger服務簡要介紹和學習計劃
- 啟動過程分析
- 對幀緩沖區(Frame Buffer)的管理分析
- 線程模型分析
- 渲染應用程序UI的過程分析
- Android應用程序與SurfaceFlinger服務的關系
- 概述和學習計劃
- 連接過程分析
- 共享UI元數據(SharedClient)的創建過程分析
- 創建Surface的過程分析
- 渲染Surface的過程分析
- Android應用程序窗口(Activity)
- 實現框架簡要介紹和學習計劃
- 運行上下文環境(Context)的創建過程分析
- 窗口對象(Window)的創建過程分析
- 視圖對象(View)的創建過程分析
- 與WindowManagerService服務的連接過程分析
- 繪圖表面(Surface)的創建過程分析
- 測量(Measure)、布局(Layout)和繪制(Draw)過程分析
- WindowManagerService
- WindowManagerService的簡要介紹和學習計劃
- 計算Activity窗口大小的過程分析
- 對窗口的組織方式分析
- 對輸入法窗口(Input Method Window)的管理分析
- 對壁紙窗口(Wallpaper Window)的管理分析
- 計算窗口Z軸位置的過程分析
- 顯示Activity組件的啟動窗口(Starting Window)的過程分析
- 切換Activity窗口(App Transition)的過程分析
- 顯示窗口動畫的原理分析
- Android控件TextView的實現原理分析
- Android視圖SurfaceView的實現原理分析
- Android應用程序UI硬件加速渲染
- 簡要介紹和學習計劃
- 環境初始化過程分析
- 預加載資源地圖集服務(Asset Atlas Service)分析
- Display List構建過程分析
- Display List渲染過程分析
- 動畫執行過程分析
- Android應用程序資源管理框架
- Android資源管理框架(Asset Manager)
- Asset Manager 簡要介紹和學習計劃
- 編譯和打包過程分析
- Asset Manager的創建過程分析
- 查找過程分析
- Dalvik虛擬機和ART虛擬機
- Dalvik虛擬機
- Dalvik虛擬機簡要介紹和學習計劃
- Dalvik虛擬機的啟動過程分析
- Dalvik虛擬機的運行過程分析
- Dalvik虛擬機JNI方法的注冊過程分析
- Dalvik虛擬機進程和線程的創建過程分析
- Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃
- Dalvik虛擬機Java堆創建過程分析
- Dalvik虛擬機為新創建對象分配內存的過程分析
- Dalvik虛擬機垃圾收集(GC)過程分析
- ART虛擬機
- Android ART運行時無縫替換Dalvik虛擬機的過程分析
- Android運行時ART簡要介紹和學習計劃
- Android運行時ART加載OAT文件的過程分析
- Android運行時ART加載類和方法的過程分析
- Android運行時ART執行類方法的過程分析
- ART運行時垃圾收集機制簡要介紹和學習計劃
- ART運行時Java堆創建過程分析
- ART運行時為新創建對象分配內存的過程分析
- ART運行時垃圾收集(GC)過程分析
- ART運行時Compacting GC簡要介紹和學習計劃
- ART運行時Compacting GC堆創建過程分析
- ART運行時Compacting GC為新創建對象分配內存的過程分析
- ART運行時Semi-Space(SS)和Generational Semi-Space(GSS)GC執行過程分析
- ART運行時Mark-Compact( MC)GC執行過程分析
- ART運行時Foreground GC和Background GC切換過程分析
- Android安全機制
- SEAndroid安全機制簡要介紹和學習計劃
- SEAndroid安全機制框架分析
- SEAndroid安全機制中的文件安全上下文關聯分析
- SEAndroid安全機制中的進程安全上下文關聯分析
- SEAndroid安全機制對Android屬性訪問的保護分析
- SEAndroid安全機制對Binder IPC的保護分析
- 從NDK在非Root手機上的調試原理探討Android的安全機制
- APK防反編譯
- Android視頻硬解穩定性問題探討和處理
- Android系統的智能指針(輕量級指針、強指針和弱指針)的實現原理分析
- Android應用程序安裝過程源代碼分析
- Android應用程序啟動過程源代碼分析
- 四大組件源代碼分析
- Activity
- Android應用程序的Activity啟動過程簡要介紹和學習計劃
- Android應用程序內部啟動Activity過程(startActivity)的源代碼分析
- 解開Android應用程序組件Activity的"singleTask"之謎
- Android應用程序在新的進程中啟動新的Activity的方法和過程分析
- Service
- Android應用程序綁定服務(bindService)的過程源代碼分析
- ContentProvider
- Android應用程序組件Content Provider簡要介紹和學習計劃
- Android應用程序組件Content Provider應用實例
- Android應用程序組件Content Provider的啟動過程源代碼分析
- Android應用程序組件Content Provider在應用程序之間共享數據的原理分析
- Android應用程序組件Content Provider的共享數據更新通知機制分析
- BroadcastReceiver
- Android系統中的廣播(Broadcast)機制簡要介紹和學習計劃
- Android應用程序注冊廣播接收器(registerReceiver)的過程分析
- Android應用程序發送廣播(sendBroadcast)的過程分析