[原文出處----------------ART運行時Compacting GC堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/44789295)
引進了Compacting GC之后,ART運行時的堆空間結構就發生了變化。這是由于Compacting GC和Mark-Sweep GC的算法不同,要求底層的堆具有不同的空間結構。同時,即使是原來的Mark-Sweep GC,由于需要支持新的同構空間壓縮特性(Homogeneous Space Compact),也使得它們要具有與原來不一樣的堆空間結構。本文就對這些堆空間創建過程進行詳細的分析。
從前面[ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)一文可以知道,在沒有Compacting GC之前,Mark-Sweep GC的堆由Image Space、Zygote Space、Allocation Space和Large Object Space四種Space組成。其中,Allocation Space是從Zygote Space中分離出來的,它們都是一種DlMallocSpace。引入Compacting GC之后,Image Space和Large Object Space沒有發生根本性的變化,但是Zygote Space和Allocation Space就發生了很大的變化。因此,接下來我們就結合Compacting GC以及其它的一些新特性來分析Zygote Space和Allocation Space都發生了哪些變化。
從前面[ART運行時Compacting GC簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/44513977)一文可以知道,用來分配對象的空間可以是一種DlMallocSpace,也可以是一種RosAllocSpace,因此,堆空間發生的第一個變化是用來分配對象的空間有可能是一個DlMallocSpace,也有可能是一個RosAllocSpace。
從前面[ART運行時Compacting GC簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/44513977)一文還可以知道,Semi-Space GC需要兩個Bump Pointer Space,Generational Semi-Space GC需要兩個Bump Pointer Space和一個Promote Space,Mark-Compact GC需要一個Bump Pointer Space。因此,我們需要增加一種類型為Bump Pointer的Space,以及一個Promote Space。
此外,我們還需要一個Non-Moving Space。由于在Compacting GC中,涉及到對象的移動,但是有些對象,例如類對象(Class)、類方法對象(ArtMethod)和類成員變量對象(ArtField),它們一經加載后,基本上就會一直存在。因此,頻繁對此類對象進行移動是無益的,我們需要將它們分配在一個不能移動的Space中,以減少在Compacting GC需要處理的對象的數量。
所謂的同構空間壓縮特性(Homogeneous Space Compact),是針對Mark-Sweep GC而言的。一個Space需要有Main和Backup之分。執行同構空間壓縮時,將Main Space的對象移動至Backup Space中去,再將Main Space和Backup Space進行交換,這樣就達到壓縮空間,即減少內存碎片的作用。
綜合前面的分析,我們就列出ART運行時支持的各種GC的堆空間結構,如下三個圖所示:

圖1 Mark-Sweep GC的堆空間結構

圖2 Semi-Space GC和Mark-Compact GC的堆空間結構

圖3 Generational Semi-Space GC的堆空間結構
接下來,我們將結構源代碼來詳細分析上述三個圖各個Space的創建過程,這樣就可以更好理解這三個圖所表達的意思。
從前面[ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)一文可以知道,堆的創建是從在ART運行時內部創建一個Heap對象開始的,如下所示:
~~~
bool Runtime::Init(const RuntimeOptions& raw_options, bool 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->foreground_heap_growth_multiplier_,
options->heap_maximum_size_,
options->heap_non_moving_space_capacity_,
options->image_,
options->image_isa_,
options->collector_type_,
options->background_collector_type_,
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_,
options->use_tlab_,
options->verify_pre_gc_heap_,
options->verify_pre_sweeping_heap_,
options->verify_post_gc_heap_,
options->verify_pre_gc_rosalloc_,
options->verify_pre_sweeping_rosalloc_,
options->verify_post_gc_rosalloc_,
options->use_homogeneous_space_compaction_for_oom_,
options->min_interval_homogeneous_space_compaction_by_oom_);
......
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
創建堆所需要的一般性參數的含義可以參考前面ART運行時Java堆創建過程分析一文,這里我們只解釋幾個與Compacting GC相關的參數:
* **options->heap_non_moving_space_capacity_**:Non-Moving Space的大小,可以通過ART運行時啟動選項-XX:NonMovingSpaceCapacity來指定,默認大小為kDefaultNonMovingSpaceCapacity(64MB)。
* **options->collector_type_**:Foreground GC的類型,可以通過ART運行時啟動選項-Xgc指定。如果沒有指定,在編譯ART運行時時,可以通過ART_DEFAULT_GC_TYPE_IS_CMS、ART_DEFAULT_GC_TYPE_IS_SS和ART_DEFAULT_GC_TYPE_IS_GSS這三個宏分別默認為Concurrent Mark-Sweep GC、Semi-Space GC或者Generational Semi-Space GC。
* **options->background_collector_type_**:Background GC的類型,可以通過ART運行時啟動選項-XX:BackgroundGC指定。如果沒有指定,在編譯ART運行時時,可以通過ART_USE_HSPACE_COMPACT宏指定為Homogeneous-Space-Compact。如果沒有指定ART_USE_HSPACE_COMPACT宏,默認就與Foreground GC一樣。
* **options->use_homogeneous_space_compaction_for_oom_**:是否在OOM時執行Homogeneous-Space-Compact,可以通過ART運行時啟動選項-XX:EnableHSpaceCompactForOOM和-XX:DisableHSpaceCompactForOOM來設置為支持和不支持。如果沒有指定,默認不支持。
* **options->min_interval_homogeneous_space_compaction_by_oom_**:OOM時執行Homogeneous-Space-Compact的最小時間間隔,可以在OOM時頻繁地執行Homogeneous-Space-Compact,固定為100秒。
Heap對象的創建和初始化過程如下所示:
~~~
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, double foreground_heap_growth_multiplier,
size_t capacity, size_t non_moving_space_capacity, const std::string& image_file_name,
const InstructionSet image_instruction_set, CollectorType foreground_collector_type,
CollectorType background_collector_type, 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, bool use_tlab,
bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
bool verify_pre_gc_rosalloc, bool verify_pre_sweeping_rosalloc,
bool verify_post_gc_rosalloc, bool use_homogeneous_space_compaction_for_oom,
uint64_t min_interval_homogeneous_space_compaction_by_oom)
......
byte* requested_alloc_space_begin = nullptr;
if (!image_file_name.empty()) {
std::string error_msg;
space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str(),
image_instruction_set,
&error_msg);
if (image_space != nullptr) {
AddSpace(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();
......
requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
}
......
}
......
bool support_homogeneous_space_compaction =
background_collector_type_ == gc::kCollectorTypeHomogeneousSpaceCompact ||
use_homogeneous_space_compaction_for_oom;
// We may use the same space the main space for the non moving space if we don't need to compact
// from the main space.
// This is not the case if we support homogeneous compaction or have a moving background
// collector type.
bool separate_non_moving_space = is_zygote ||
support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) ||
IsMovingGc(background_collector_type_);
if (foreground_collector_type == kCollectorTypeGSS) {
separate_non_moving_space = false;
}
std::unique_ptr<MemMap> main_mem_map_1;
std::unique_ptr<MemMap> main_mem_map_2;
byte* request_begin = requested_alloc_space_begin;
if (request_begin != nullptr && separate_non_moving_space) {
request_begin += non_moving_space_capacity;
}
......
std::unique_ptr<MemMap> non_moving_space_mem_map;
if (separate_non_moving_space) {
// Reserve the non moving mem map before the other two since it needs to be at a specific
// address.
non_moving_space_mem_map.reset(
MemMap::MapAnonymous("non moving space", requested_alloc_space_begin,
non_moving_space_capacity, PROT_READ | PROT_WRITE, true, &error_str));
......
// Try to reserve virtual memory at a lower address if we have a separate non moving space.
request_begin = reinterpret_cast<byte*>(300 * MB);
}
// Attempt to create 2 mem maps at or after the requested begin.
main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_,
PROT_READ | PROT_WRITE, &error_str));
......
if (support_homogeneous_space_compaction ||
background_collector_type_ == kCollectorTypeSS ||
foreground_collector_type_ == kCollectorTypeSS) {
main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(),
capacity_, PROT_READ | PROT_WRITE,
&error_str));
......
}
// Create the non moving space first so that bitmaps don't take up the address range.
if (separate_non_moving_space) {
// Non moving space is always dlmalloc since we currently don't have support for multiple
// active rosalloc spaces.
const size_t size = non_moving_space_mem_map->Size();
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_);
}
// Create other spaces based on whether or not we have a moving GC.
if (IsMovingGc(foreground_collector_type_) && foreground_collector_type_ != kCollectorTypeGSS) {
// Create bump pointer spaces.
// We only to create the bump pointer if the foreground collector is a compacting GC.
// TODO: Place bump-pointer spaces somewhere to minimize size of card table.
bump_pointer_space_ = space::BumpPointerSpace::CreateFromMemMap("Bump pointer space 1",
main_mem_map_1.release());
......
AddSpace(bump_pointer_space_);
temp_space_ = space::BumpPointerSpace::CreateFromMemMap("Bump pointer space 2",
main_mem_map_2.release());
......
AddSpace(temp_space_);
......
} else {
CreateMainMallocSpace(main_mem_map_1.release(), initial_size, growth_limit_, capacity_);
......
AddSpace(main_space_);
if (!separate_non_moving_space) {
non_moving_space_ = main_space_;
......
}
if (foreground_collector_type_ == kCollectorTypeGSS) {
......
// Create bump pointer spaces instead of a backup space.
main_mem_map_2.release();
bump_pointer_space_ = space::BumpPointerSpace::Create("Bump pointer space 1",
kGSSBumpPointerSpaceCapacity, nullptr);
......
AddSpace(bump_pointer_space_);
temp_space_ = space::BumpPointerSpace::Create("Bump pointer space 2",
kGSSBumpPointerSpaceCapacity, nullptr);
......
AddSpace(temp_space_);
} else if (main_mem_map_2.get() != nullptr) {
const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1];
main_space_backup_.reset(CreateMallocSpaceFromMemMap(main_mem_map_2.release(), initial_size,
growth_limit_, capacity_, name, true));
......
// Add the space so its accounted for in the heap_begin and heap_end.
AddSpace(main_space_backup_.get());
}
}
......
}
~~~
這個函數定義在文件art/runtime/gc/heap.cc中。
由于底層堆的空間結構要兼顧到上層的各種GC,因此堆創建過程中涉及到邏輯是比較復雜的,我們將上述函數涉及到的代碼分段來解讀。
第一段代碼是關于Image Space的創建的,如下所示:
~~~
byte* requested_alloc_space_begin = nullptr;
if (!image_file_name.empty()) {
std::string error_msg;
space::ImageSpace* image_space = space::ImageSpace::Create(image_file_name.c_str(),
image_instruction_set,
&error_msg);
if (image_space != nullptr) {
AddSpace(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();
......
requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
}
......
}
~~~
關于Image Space的創建過程,可以參考前面[ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)一文。從前面[ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)一文可以知道,緊跟在Image Space后面的是一個boot.art@classes.oat文件。而緊跟在boot.art@classes.oat文件末尾的Zygote Space,這個地址記錄在本地變量requested_alloc_space_begin中。
第二段代碼是關于Non-Moving Space的,如下所示:
~~~
bool support_homogeneous_space_compaction =
background_collector_type_ == gc::kCollectorTypeHomogeneousSpaceCompact ||
use_homogeneous_space_compaction_for_oom;
// We may use the same space the main space for the non moving space if we don't need to compact
// from the main space.
// This is not the case if we support homogeneous compaction or have a moving background
// collector type.
bool separate_non_moving_space = is_zygote ||
support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) ||
IsMovingGc(background_collector_type_);
if (foreground_collector_type == kCollectorTypeGSS) {
separate_non_moving_space = false;
}
std::unique_ptr<MemMap> main_mem_map_1;
std::unique_ptr<MemMap> main_mem_map_2;
byte* request_begin = requested_alloc_space_begin;
if (request_begin != nullptr && separate_non_moving_space) {
request_begin += non_moving_space_capacity;
}
......
std::unique_ptr<MemMap> non_moving_space_mem_map;
if (separate_non_moving_space) {
// Reserve the non moving mem map before the other two since it needs to be at a specific
// address.
non_moving_space_mem_map.reset(
MemMap::MapAnonymous("non moving space", requested_alloc_space_begin,
non_moving_space_capacity, PROT_READ | PROT_WRITE, true, &error_str));
......
// Try to reserve virtual memory at a lower address if we have a separate non moving space.
request_begin = reinterpret_cast<byte*>(300 * MB);
}
~~~
這段代碼的邏輯是判斷是否需要給Non-Moving Space一個獨立的地址空間。Non-Moving Space總是存在的,現在需要判斷的是要給它一個獨立的地址空間,還是要與其它Space共享同一個地址空間,主要是考慮到Generational Semi-Space GC。
從前面[ART運行時Compacting GC簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/44513977)一文可以知道,Generational Semi-Space GC需要一個Promote Space來保存那些經過若干輪GC后仍然存活下來的對象,而且這些對象在以后的Generational Semi-Space GC中不需要進行移動。這個Promote Space就是一個DlMallocSpace或者RosAllocSpace。Promote Space起到的作用與Non-Moving Space類似,因為保存在它們里面的對象都是不可以移動的。因此,在Generational Semi-Space GC的情況下,將Promote Space和Non-Moving Space合在一起共享同一個地址空間。
Non-Moving Space是相對Moving Space而言的,也就是說,只要存在Moving Space,就需要給Non-Moving Space一個獨立的地址空間,使得在Non-Moving Space和Moving Space的對象在GC中可以區別對待處理。
那么,在什么情況下存在Moving Space呢?最直覺地,只要我們使用到了Compacting GC,那么就需要Moving Space,因為Compacting GC需要移動對象。因此,上述代碼段會調用Heap類的成員函數IsMovingGc判斷指定的Foreground GC(foreground_collector_type_)和Background GC(background_collector_type_)是否是Compacting GC,也就是是否是Semi-Space GC、Generational Semi-Space GC和Mark-Compact GC之一。如果是的話,那么就將本地變量separate_non_moving_space設置為true,表示需要給Non-Moving Space一個獨立的地址空間。
除了Compacting GC的情況,還有兩種情況也是涉及到Moving Space的。
* 第一種情況是應用程序運行在Zygote模式中,即本地變量is_zygote等于true的情況下。應用程序運行在Zygote模式時,它們的進程都是由Zygote進程fork出來的,這樣做的目的是為了讓Zygote進程和應用程序進程共享內存。Zygote進程在fork第一個應用程序進程之前,為了有效地和應用程序進程共享內存,會對堆空間進行一次壓縮處理。這個壓縮處理實際上就是執行一次Semi-Space GC。因此,在這種情況下,即本地變量is_zygote等于true時,也需要將本地變量separate_non_moving_space設置為true,表示需要給Non-Moving Space一個獨立的地址空間。
* 第二種情況ART運行時支持Homogeneous-Space-Compact特性。Homogeneous-Space-Compact特性意味我們要將Main Space上的對象移動到Backup Space上去。這個移動過程實際上也是通過執行一次Semi-Space GC來完成的。因此,在這種情況下,即本地變量support_homogeneous_space_compaction等于true時,也需要將本地變量separate_non_moving_space設置為true,表示需要給Non-Moving Space一個獨立的地址空間。
那么,什么情況下ART運行時需要支持Homogeneous-Space-Compact特性呢?有兩種情況需要支持。
* 第一種情況是Background GC(background_collector_type_)被指定為Homogeneous-Space-Compact GC,這可以通過ART運行時啟動選項-XX:BackgroundGC進行指定。
* 第二種情況是在分配對象遇到OOM時,需要將Main Space上的對象移動到Backup Space上去,然后再將這兩個Space進行交換,并且再次嘗試在Main Space上進行分配,以便可以解決由內存碎片引發的OOM問題。我們可以通過ART運行時啟動選項-XX:EnableHSpaceCompactForOOM和-XX:DisableHSpaceCompactForOOM來啟用和禁用這種行為,體現在這里就是參數use_homogeneous_space_compaction_for_oom的值是等于true還是false。
一旦決定給Non-Moving Space一個獨立的地址空間,那么就會調用MemMap類的靜態成員函數MapAnonymous創建一塊匿名共享內存non_moving_space_mem_map,以便接下來可以用來創建Non-Moving Space。注意,這塊匿名共享內存的起始地址緊接著在boot.art@classes.oat的末尾。同時,其它的Space的起始地址request_begin被修改為300MB地址處,即它們不再是緊跟著Non-Moving Space的末尾。
第三段代碼用來創建另外兩塊匿名共享內存,如下所示:
~~~
// Attempt to create 2 mem maps at or after the requested begin.
main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_,
PROT_READ | PROT_WRITE, &error_str));
......
if (support_homogeneous_space_compaction ||
background_collector_type_ == kCollectorTypeSS ||
foreground_collector_type_ == kCollectorTypeSS) {
main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(),
capacity_, PROT_READ | PROT_WRITE,
&error_str));
......
}
~~~
第一塊匿名共享內存main_mem_map_1用來創建Compacting GC的From Bump Pointer Space或者Mark-Sweep GC的Main Space。第二塊匿名共享內存main_mem_map_2用來創建Semi-Space GC的To Bump Pointer Space或者Mark-Sweep GC的Backup Space。注意,第二塊匿名共享內存main_mem_map_2緊跟在第一塊匿名共享內存main_mem_map_1的末尾。
第四段代碼用來創建Non-Moving Space,如下所示:
~~~
// Create the non moving space first so that bitmaps don't take up the address range.
if (separate_non_moving_space) {
// Non moving space is always dlmalloc since we currently don't have support for multiple
// active rosalloc spaces.
const size_t size = non_moving_space_mem_map->Size();
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_);
}
~~~
只有在本地變量separate_non_moving_space等于true的情況下,也就是要給Non-Moving Space一塊獨立的地址空間的情況下,這里才會將前面創建的匿名共享內存non_moving_space_mem_map封裝成一個DlMallocSpace,作為一塊獨立的Non-Moving Space使用。
第五段代碼用來為Compacting GC創建Bump Pointer Space或者為Mark-Sweep GC創建Main Space和Backup Space,如下所示:
~~~
// Create other spaces based on whether or not we have a moving GC.
if (IsMovingGc(foreground_collector_type_) && foreground_collector_type_ != kCollectorTypeGSS) {
// Create bump pointer spaces.
// We only to create the bump pointer if the foreground collector is a compacting GC.
// TODO: Place bump-pointer spaces somewhere to minimize size of card table.
bump_pointer_space_ = space::BumpPointerSpace::CreateFromMemMap("Bump pointer space 1",
main_mem_map_1.release());
......
AddSpace(bump_pointer_space_);
temp_space_ = space::BumpPointerSpace::CreateFromMemMap("Bump pointer space 2",
main_mem_map_2.release());
......
AddSpace(temp_space_);
......
} else {
CreateMainMallocSpace(main_mem_map_1.release(), initial_size, growth_limit_, capacity_);
......
AddSpace(main_space_);
if (!separate_non_moving_space) {
non_moving_space_ = main_space_;
......
}
if (foreground_collector_type_ == kCollectorTypeGSS) {
......
// Create bump pointer spaces instead of a backup space.
main_mem_map_2.release();
bump_pointer_space_ = space::BumpPointerSpace::Create("Bump pointer space 1",
kGSSBumpPointerSpaceCapacity, nullptr);
......
AddSpace(bump_pointer_space_);
temp_space_ = space::BumpPointerSpace::Create("Bump pointer space 2",
kGSSBumpPointerSpaceCapacity, nullptr);
......
AddSpace(temp_space_);
} else if (main_mem_map_2.get() != nullptr) {
const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1];
main_space_backup_.reset(CreateMallocSpaceFromMemMap(main_mem_map_2.release(), initial_size,
growth_limit_, capacity_, name, true));
......
// Add the space so its accounted for in the heap_begin and heap_end.
AddSpace(main_space_backup_.get());
}
}
~~~
當Foreground GC是Compacting GC,但是不是Generational Semi-Space GC時,分別是用前面創建的匿名共享內存main_mem_map_1和main_mem_map_2創建兩個Bump Pointer Space,并且保存在Heap類的成員變量bump_pointer_space_和temp_space_中。
當Foreground GC是Mark-Sweep GC或者Generational Semi-Space GC時,首先是調用Heap類的成員函數CreateMainMallocSpace創建一個Main Space,這個Main Space是一塊DlMallocSpace或者RosAllocSpace,并且由Heap類的成員變量main_space_指向。
如果Foreground GC是Generational Semi-Space GC,上面創建的Main Space實際上是作為Promote Space來使用的。同時由前面的分析可以知道,本地變量separate_non_moving_space的值這時候等于false,這意味著Non-Moving Space與上述Promote Space共享的是同一個地址空間。也就是此時ART運行時的Non-Moving Space(non_moving_space_)與Generational Semi-Space GC的Promote Space(main_space_)指向的是一個Space。接下來,上述代碼還會繼續為Generational Semi-Space GC創建一個From Bump Pointer Space和一個To Bump Pointer Space。這兩個Bump Pointer Space是通過封裝兩塊新創建的匿名共享內存得到的。
如果Foreground GC是Mark-Sweep GC,則它們所需要的Main Space前面已經創建完畢,現在只需要再創建一個Backup Space即可。通過調用Heap類的成員函數CreateMallocSpaceFromMemMap即可創建一個DlMallocSpace或者RosAllocSpace,以作為Backup Space使用,并且由Heap類的成員變量main_space_backup_指向。
接下來我們繼續分析Heap類的成員函數CreateMainMallocSpace的實現,以便可以了解Main Space的創建過程,而且從中也可以看到用來創建Backup Space的Heap類的成員函數CreateMallocSpaceFromMemMap的實現,如下所示:
~~~
void Heap::CreateMainMallocSpace(MemMap* mem_map, size_t initial_size, size_t growth_limit,
size_t capacity) {
// Is background compaction is enabled?
bool can_move_objects = IsMovingGc(background_collector_type_) !=
IsMovingGc(foreground_collector_type_) || use_homogeneous_space_compaction_for_oom_;
// If we are the zygote and don't yet have a zygote space, it means that the zygote fork will
// happen in the future. If this happens and we have kCompactZygote enabled we wish to compact
// from the main space to the zygote space. If background compaction is enabled, always pass in
// that we can move objets.
if (kCompactZygote && Runtime::Current()->IsZygote() && !can_move_objects) {
// After the zygote we want this to be false if we don't have background compaction enabled so
// that getting primitive array elements is faster.
// We never have homogeneous compaction with GSS and don't need a space with movable objects.
can_move_objects = !have_zygote_space_ && foreground_collector_type_ != kCollectorTypeGSS;
}
if (collector::SemiSpace::kUseRememberedSet && main_space_ != nullptr) {
RemoveRememberedSet(main_space_);
}
const char* name = kUseRosAlloc ? kRosAllocSpaceName[0] : kDlMallocSpaceName[0];
main_space_ = CreateMallocSpaceFromMemMap(mem_map, initial_size, growth_limit, capacity, name,
can_move_objects);
SetSpaceAsDefault(main_space_);
VLOG(heap) << "Created main space " << main_space_;
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
一般來說,在以下兩種情況下,Main Space的對象可以移動:
1. Foreground GC和Background GC不同時為Compacting GC或者Mark-Sweep GC。這是因為當發生Foreground GC和Background GC切換時,如果Foreground GC和Background GC不同時為Compacting GC或者Mark-Sweep GC時,需要將對象從Main Space移動到Bump Pointer Space,或者從Bump Pointer Space移動到Main Space。
2. ART運行時分配對象發生OOM時支持Homogeneous-Space-Compact特性。這時候需要將Main Space的對象移動到Backup Space。
還有一種特殊情況,要求Main Space上的對象是可以移動的。前面提到,Zygote進程在fork第一個應用程序進程之前,會對堆進行一次Semi-Space GC。取決于當前的Foreground GC是Compacting GC還是Mark-Sweep GC,這次Semi-Space GC的From Space即為Compacting GC當前使用的Bump Pointer Space或者Mark-Sweep GC的Main Space。不過這樣的Semi-Space GC是要在常量kCompactZygote設置為true的情況下才會執行。
根據前面的分析,在Foreground GC是Generational Semi-Space GC的情況下,這里創建的Main Space同時也作為Generational Semi-Space GC的Promote Space,這就要求Main Space是不能移動對象的。
有了這些背景知識后,就可以很容易理解Heap類的成員函數CreateMallocSpaceFromMemMap的實現了。首先,語句IsMovingGc(background_collector_type_) != IsMovingGc(foreground_collector_type_)就是用來判斷Foreground GC和Background GC不同時為Compacting GC或者Mark-Sweep GC的。其次,use_homogeneous_space_compaction_for_oom_代表ART運行時分配對象發生OOM時支持Homogeneous-Space-Compact特性。
如果經過上面的處理之后,本地變量can_move_objects的值仍然為false,并且當前是運行在Zygote模式中(Runtime::Current()->IsZygote()等于true)、常量kCompactZygote為true,那么就會接著判斷當前是否處于Zygote進程fork第一個應用程序進程之前,即Heap類的成員變量have_zygote_space_等于false。如果是的話,那么就會在當前的Foreground GC不是Generational Semi-Space GC的情況下,將本地變量can_move_objects修改為true,以便接下來調用Heap類的成員函數CreateMallocSpaceFromMemMap創建一個DlMallocSpace或者RosAllocSpace,如下所示:
~~~
space::MallocSpace* Heap::CreateMallocSpaceFromMemMap(MemMap* mem_map, size_t initial_size,
size_t growth_limit, size_t capacity,
const char* name, bool can_move_objects) {
space::MallocSpace* malloc_space = nullptr;
if (kUseRosAlloc) {
// Create rosalloc space.
malloc_space = space::RosAllocSpace::CreateFromMemMap(mem_map, name, kDefaultStartingSize,
initial_size, growth_limit, capacity,
low_memory_mode_, can_move_objects);
} else {
malloc_space = space::DlMallocSpace::CreateFromMemMap(mem_map, name, kDefaultStartingSize,
initial_size, growth_limit, capacity,
can_move_objects);
}
if (collector::SemiSpace::kUseRememberedSet) {
accounting::RememberedSet* rem_set =
new accounting::RememberedSet(std::string(name) + " remembered set", this, malloc_space);
CHECK(rem_set != nullptr) << "Failed to create main space remembered set";
AddRememberedSet(rem_set);
}
CHECK(malloc_space != nullptr) << "Failed to create " << name;
malloc_space->SetFootprintLimit(malloc_space->Capacity());
return malloc_space;
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
如果常量kUseRosAlloc的值等于true,那么就Heap類的成員函數CreateMallocSpaceFromMemMap創建的是一個RosAllocSpace;否則的話,創建的是一個DlMallocSpace。同時,如果常量collector::SemiSpace::kUseRememberedSet的值等于true,那么就為前面創建的RosAllocSpace或者DlMallocSpace創建一個RememberedSet。RememberedSet與在前面[ART運行時垃圾收集機制簡要介紹和學習計劃](http://blog.csdn.net/luoshengyang/article/details/42072975)這個系列文章提到的ModUnionTable的作用類似,都是用來記錄被修改對象對指定目標空間的對象的引用情況的。
回到Heap類的成員函數CreateMainMallocSpace中,調用Heap類的成員函數CreateMallocSpaceFromMemMap創建完成Main Space之后,還會調用另外一個成員函數SetSpaceAsDefault將該Main Space設置為當前Mark-Sweep GC使用的Main Space或者當前Generational Semi-Space GC使用的Promote Space,如下所示:
~~~
void Heap::SetSpaceAsDefault(space::ContinuousSpace* continuous_space) {
WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
if (continuous_space->IsDlMallocSpace()) {
dlmalloc_space_ = continuous_space->AsDlMallocSpace();
} else if (continuous_space->IsRosAllocSpace()) {
rosalloc_space_ = continuous_space->AsRosAllocSpace();
}
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
如果前面創建的Main Space是一個DlMallocSpace,那么就將它保存在Heap類的成員變量dlmalloc_space_中;否則的話,如果是一個RosAllocSpace,就保存在Heap類的成員變量rosalloc_space_中。
設置好Heap類的成員變量dlmalloc_space_和rosalloc_space_之后,以后在分配對象時,就可以通過kAllocatorTypeDlMalloc或者kAllocatorTypeRosAlloc常量指定是要DlMallocSpace中分配對象,還是在RosAllocSpace中分配對象,以及Generational Semi-Space GC可以通過它們獲得對應的Promote Space來保存那些經過若干輪GC仍然存活下來的對象。
代碼分析到這里,我們就基本上把圖1、圖2和圖3涉及到的知識都解釋完畢,大家可以對照著重新理解一下。不過,在圖1、圖2和圖3中,我們還沒有解釋到的一個點就是Zygote Space是怎么來的。接下來我們就繼續分析Zygote Space的創建過程。
Zygote Space是從Non-Moving Space分割而來的。具體來說,就是在Zygote進程fork第一個應用程序進程之前,會調用Heap類的成員函數PreZygoteFork創建一個Zygote Space,它的實現如下所示:
~~~
void Heap::PreZygoteFork() {
CollectGarbageInternal(collector::kGcTypeFull, kGcCauseBackground, 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;
}
......
// Trim the pages at the end of the non moving space.
non_moving_space_->Trim();
// The end of the non-moving space may be protected, unprotect it so that we can copy the zygote
// there.
non_moving_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
const bool same_space = non_moving_space_ == main_space_;
if (kCompactZygote) {
......
// Temporarily disable rosalloc verification because the zygote
// compaction will mess up the rosalloc internal metadata.
ScopedDisableRosAllocVerification disable_rosalloc_verif(this);
ZygoteCompactingCollector zygote_collector(this);
zygote_collector.BuildBins(non_moving_space_);
// Create a new bump pointer space which we will compact into.
space::BumpPointerSpace target_space("zygote bump space", non_moving_space_->End(),
non_moving_space_->Limit());
// Compact the bump pointer space to a new zygote bump pointer space.
bool reset_main_space = false;
if (IsMovingGc(collector_type_)) {
zygote_collector.SetFromSpace(bump_pointer_space_);
} else {
......
// Copy from the main space.
zygote_collector.SetFromSpace(main_space_);
reset_main_space = true;
}
zygote_collector.SetToSpace(&target_space);
zygote_collector.SetSwapSemiSpaces(false);
zygote_collector.Run(kGcCauseCollectorTransition, false);
if (reset_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, mem_map->Size(), mem_map->Size());
delete old_main_space;
AddSpace(main_space_);
}
......
}
......
space::MallocSpace* old_alloc_space = non_moving_space_;
......
space::ZygoteSpace* zygote_space = old_alloc_space->CreateZygoteSpace("alloc space",
low_memory_mode_,
&non_moving_space_);
......
if (same_space) {
main_space_ = non_moving_space_;
SetSpaceAsDefault(main_space_);
}
delete old_alloc_space;
......
AddSpace(zygote_space);
non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
AddSpace(non_moving_space_);
have_zygote_space_ = true;
......
accounting::ModUnionTable* mod_union_table =
new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space);
......
AddModUnionTable(mod_union_table);
if (collector::SemiSpace::kUseRememberedSet) {
// Add a new remembered set for the post-zygote non-moving space.
accounting::RememberedSet* post_zygote_non_moving_space_rem_set =
new accounting::RememberedSet("Post-zygote non-moving space remembered set", this,
non_moving_space_);
......
AddRememberedSet(post_zygote_non_moving_space_rem_set);
}
}
~~~
這個函數定義在文件art/runtime/runtime.cc中。
Heap類的成員函數PreZygoteFork用來從Non-Moving Space中分割出一個Zygote Space來。在分割之前,如果需要的話,還會對Main Space或者Bump Pointer Space的對象進行壓縮處理。我們分成三小段代碼來閱讀這個函數。
第一段代碼是對堆進行一次GC和裁剪處理,如下所示:
~~~
CollectGarbageInternal(collector::kGcTypeFull, kGcCauseBackground, 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;
}
......
// Trim the pages at the end of the non moving space.
non_moving_space_->Trim();
// The end of the non-moving space may be protected, unprotect it so that we can copy the zygote
// there.
non_moving_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
const bool same_space = non_moving_space_ == main_space_;
~~~
對堆進行GC處理是通過調用Heap類的成員函數CollectGarbageInternal來實現的。接下來,判斷Heap類的成員變量have_zygote_space_的值是否等于true。如果等于的話,就說明Zygote Space已經創建過了,因此就不用再往下處理。否則的話,再繼續調用Heap類的成員變量non_moving_space_指向的一個DlMallocSpace或者RosAllocSpace對象的成員函數Trim對它未使用的內存進行裁剪,即將這些未使用的內存歸還給內核。最后,將Non-Moving Space內部使用的匿名共享內存塊設置為可讀可寫,并且記錄好Non-Moving Space和Main Space是否共用同一塊匿名共享內存。這里之所以要將Non-Moving Space內部使用的匿名共享內存塊設置為可讀可寫,是因為接下來我們要將Main Space或者Bump Pointer Space上的對象移動到Non-Moving Space上去。
第二段代碼是將Main Space或者Bump Pointer Space上的對象移動到Non-Moving Space上去,如下所示:
~~~
if (kCompactZygote) {
......
// Temporarily disable rosalloc verification because the zygote
// compaction will mess up the rosalloc internal metadata.
ScopedDisableRosAllocVerification disable_rosalloc_verif(this);
ZygoteCompactingCollector zygote_collector(this);
zygote_collector.BuildBins(non_moving_space_);
// Create a new bump pointer space which we will compact into.
space::BumpPointerSpace target_space("zygote bump space", non_moving_space_->End(),
non_moving_space_->Limit());
// Compact the bump pointer space to a new zygote bump pointer space.
bool reset_main_space = false;
if (IsMovingGc(collector_type_)) {
zygote_collector.SetFromSpace(bump_pointer_space_);
} else {
......
// Copy from the main space.
zygote_collector.SetFromSpace(main_space_);
reset_main_space = true;
}
zygote_collector.SetToSpace(&target_space);
zygote_collector.SetSwapSemiSpaces(false);
zygote_collector.Run(kGcCauseCollectorTransition, false);
if (reset_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, mem_map->Size(), mem_map->Size());
delete old_main_space;
AddSpace(main_space_);
}
......
}
~~~
當常量kCompactZygote的值等于true的情況下,就需要將當前Main Space或者Bump Pointer Space上的對象移動到Non-Moving Space上去。
這個移動的過程是通過一個類型為ZygoteCompactingCollector的垃圾收集器來完成的。ZygoteCompactingCollector是從SemiSpace繼承下來的,這意味著它是通過執行一次Semi-Space GC來完成對象的移動過程的。
實際上,ZygoteCompactingCollector執行的是一次特殊的Semi-Space GC。通常我們執行Semi-Space GC時,涉及到From和To兩個Space。其中,From Space包含有對象,而To Space完全沒有包含對象。這樣當我們將對象從From Space移動到To Space時,就從To Space的起始位置開始保存對象。但是對于ZygoteCompactingCollector來說,它需要將Main Space或者Bump Pointer Space的對象移動到Non-Moving Space上去,但是Non-Moving Space這時候可能不是空的,也就是說,在上面已經存在一些對象,而且這些對象在地址空間上可能不是連續地存在的。
在移動對象之前,ZygoteCompactingCollector將Non-Moving Space分為兩部分。第一部分是前面包含有對象的空間,這部分空間可能存在一些空閑內存,因此就調用ZygoteCompactingCollector類的成員函數BuildBins將這些空閑內存塊的起始地址和大小記錄起來。第二部分是后面完全沒有包含對象的空間,這部分空間被封裝為一個BumpPointerSpace,作為ZygoteCompactingCollector的To Space。于是在移動對象到Non-Moving Space上的時候,就會優先考慮前面的空閑內存塊是否合適用來保存一個被移動對象。如果合適的話,就使用它;否則的話,再將被移動對象保存在To Space中。通過這種方式,就可以最有效地利用Non-Moving Space,盡最大限度減小內存碎片。
設置好ZygoteCompactingCollector的To Space之后,接下來再設置它的From Space。如果當前的Foreground GC是一個Compacting GC,那么就意味著當前使用的Space是一個Bump Pointer Space,該Bump Pointer Space由Heap類的成員變量bump_pointer_space_指向。否則的話,當前的Foreground GC就是一個Mark-Sweep GC,這意味著當前使用的Space是一個Main Space,該Main Space由Heap類的成員變量main_space_指向。在后一種情況下,還需要將本地變量reset_main_space的設置為true,表示在移動對象完成之后,需要重置Main Space。
設置好ZygoteCompactingCollector的From Space和To Space之后,就可以調用它的成員函數Run進行Semi-Space GC了。Semi-Space GC執行完畢,如果前面將本地變量reset_main_space的設置為true,就說明我們是將Main Space上的對象移動到了Non-Moving Space中。這時候Main Space就沒有什么作用了,這時候就可以將Main Space之前占用的所有內存都可以歸還給內核。但是,我們還是需要有一個Main Space的,因此,就再重新調用我們前面分析過的Heap類的成員函數CreateMainMallocSpace創建一個Main Space,并且將新創建的Main Space最初始占用的內存大小設置為kDefaultInitialSize。通過這個重置操作,就可以減少Main Space占用的內存。
第三段代碼執行從Non-Moving Space分離出Zygote Space的操作,如下所示:
~~~
space::MallocSpace* old_alloc_space = non_moving_space_;
......
space::ZygoteSpace* zygote_space = old_alloc_space->CreateZygoteSpace("alloc space",
low_memory_mode_,
&non_moving_space_);
......
if (same_space) {
main_space_ = non_moving_space_;
SetSpaceAsDefault(main_space_);
}
delete old_alloc_space;
......
AddSpace(zygote_space);
non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
AddSpace(non_moving_space_);
have_zygote_space_ = true;
......
accounting::ModUnionTable* mod_union_table =
new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space);
......
AddModUnionTable(mod_union_table);
if (collector::SemiSpace::kUseRememberedSet) {
// Add a new remembered set for the post-zygote non-moving space.
accounting::RememberedSet* post_zygote_non_moving_space_rem_set =
new accounting::RememberedSet("Post-zygote non-moving space remembered set", this,
non_moving_space_);
......
AddRememberedSet(post_zygote_non_moving_space_rem_set);
}
~~~
本地變量old_alloc_space指向舊的Non-Moving Space,通過調用它的成員函數CreateZygoteSpace可以從里面分割出一個Zygote Space出來,保存在本地變量zygote_space中,并且新的Non-Moving Space仍然保存在Heap類的成員變量non_moving_space_中。從Non-Moving Space分割出一個Zygote Space可以參考前面[ART運行時Java堆創建過程分析](http://blog.csdn.net/luoshengyang/article/details/42379729)一文分析的從Allocation Space分割出Zygote Space的方法。
從舊的Non-Moving Space分割出Zygote Space和新的Non-Moving Space之后,如果前面記錄了Main Space和Non-Moving Space共享的是同一塊地址空間,那么同時也需要修改Heap類的成員變量main_space_的值,使得它與新的Non-Moving Space指向的是同一塊地址空間,并且調用Heap類的成員函數SetSpaceAsDefault將新的Main Space設置為當前使用的DlMallocSpace或者RosAllocSpace。
接下來還需要將Heap類的成員變量have_zygote_space_設置為true,表示Zygote Space已經從Non-Moving Space分割出來了。最后,還要為新創建的Zygote Space創建一個ModUnionTable,用來記錄該Space的對象被修改時對其它Space的引用情況。同時,在常量collector::SemiSpace::kUseRememberedSet為true的情況下,為新的Non-Moving Space創建一個RememberedSet,同樣是用來記錄該Space的對象被修改時對其它Space的引用情況。
這樣,從Non-Moving Space中分割出Zygote Space的總體過程就分析完成了。由于具體過程涉及到Semi-Space GC,這里就沒有進一步展開來說,不過接下來我們會有專門的文章分析Semi-Space GC的執行過程,到時候再回過頭分析從Non-Moving Space中分割出Zygote Space的具體過程就會容易很多了。
至此,圖1、圖2和圖3涉及到的所有知識點就分析完成了,從中我們就可以了解到ART運行時引進了Compacting GC之后,內部的堆空間結構組成。這對我們后面理解ART運行時的對象分配過程以及Compacting GC的執行過程都是非常重要的。在接下來的一篇文章中,我們就對引進了Compacting GC之后的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)的過程分析