ART Runtime創建(三)--Heap的創建

Heap的創建位于/art/runtime/runtime.ccRuntime::Init方法中

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
  ...
  //-Xgc
  XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
  heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),//-Xms:8m
                       //-XX:HeapGrowthLimit:256m
                       runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
                       //-XX:HeapMinFree:512k
                       runtime_options.GetOrDefault(Opt::HeapMinFree),
                       //-XX:HeapMaxFree:8m
                       runtime_options.GetOrDefault(Opt::HeapMaxFree),
                       //-XX:HeapTargetUtilization:0.75
                       runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
                       //-XX:ForegroundHeapGrowthMultiplier
                       runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
                       //-Xmx:512m
                       runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
                       //-XX:NonMovingSpaceCapacity
                       runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
                       //-Ximage:/system/framework/boot.art
                       runtime_options.GetOrDefault(Opt::Image),
                       //imgaeinstructionset,是一個extra_info,用來hook: null
                       runtime_options.GetOrDefault(Opt::ImageInstructionSet),
                       //-Xgc:kuseReadBarrier ? gc::kCollectorTypeCC : gc::kCollectorTypeDefault
                       xgc_option.collector_type_,
                       //-XX:BackgroundGC
                       runtime_options.GetOrDefault(Opt::BackgroundGc),
                       //-XX:LargeObjectSpace
                       runtime_options.GetOrDefault(Opt::LargeObjectSpace),
                       //-XX:LargeObjectThreshold
                       runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
                       //-XX:ParallelGCThreads:0u
                       runtime_options.GetOrDefault(Opt::ParallelGCThreads),
                       //-XX:ConcGCThreads
                       runtime_options.GetOrDefault(Opt::ConcGCThreads),
                       //-XX:LowMemoryMode:false
                       runtime_options.Exists(Opt::LowMemoryMode),
                       //-XX:LongPauseLogThreshold
                       runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
                       //-XX:LongGCLogThreshold
                       runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
                       //-XX:IgnoreMaxFootprint
                       runtime_options.Exists(Opt::IgnoreMaxFootprint),
                       //-XX:UseTLAB
                       runtime_options.GetOrDefault(Opt::UseTLAB),
                       //default false
                       xgc_option.verify_pre_gc_heap_,
                       //default kIsDebugBuild
                       xgc_option.verify_pre_sweeping_heap_, 
                       //default false
                       xgc_option.verify_post_gc_heap_, 
                       //default kIsDebugBuild
                       xgc_option.verify_pre_gc_rosalloc_, 
                       // default false
                       xgc_option.verify_pre_sweeping_rosalloc_,
                       //default false
                       xgc_option.verify_post_gc_rosalloc_,
                       //default false
                       xgc_option.gcstress_,
                       //-XX:EnableHSpaceCompactForOOM
                       runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
                       //-XX:HspaceCompactForOOMMinIntervalMs
                       runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
  ...
}

一. 相關知識預熱

1.1 Garbage Collection Type

垃圾回收的算法有多種,如MarkSweep-標記清楚算法,MarkCompact-標記整理算法,Copying-復制算法等等,之前的Dalvik一直使用的是MarkSweep算法,ART則在MarkSweep的基礎上添加了對其他垃圾回收算法的支持,具體的算法可以通過-Xgc指定,如果沒有特別指定,則使用默認指定的:

// /art/smdline/cmdline_types.h
gc::CollectorType collector_type_ =  kUseReadBarrier ?
                                           // If RB is enabled (currently a build-time decision),
                                           // use CC as the default GC.
                                           gc::kCollectorTypeCC :
                                           gc::kCollectorTypeDefault;                                           

kUseReadBarrier定義在/art/runtime/globals.h

#ifdef USE_BAKER_READ_BARRIER
static constexpr bool kUseBakerReadBarrier = true;
#else
static constexpr bool kUseBakerReadBarrier = false;
#endif

#ifdef USE_BROOKS_READ_BARRIER
static constexpr bool kUseBrooksReadBarrier = true;
#else
static constexpr bool kUseBrooksReadBarrier = false;
#endif

#ifdef USE_TABLE_LOOKUP_READ_BARRIER
static constexpr bool kUseTableLookupReadBarrier = true;
#else
static constexpr bool kUseTableLookupReadBarrier = false;
#endif

static constexpr bool kUseBakerOrBrooksReadBarrier = kUseBakerReadBarrier || kUseBrooksReadBarrier;
static constexpr bool kUseReadBarrier =
    kUseBakerReadBarrier || kUseBrooksReadBarrier || kUseTableLookupReadBarrier;

kUseReadBarrier根據三個編譯宏決定true或false,只要這個三個編譯宏中有一個存在,則kUseReadBarrier=true

gc::kCollectorTypeCCgc::kCollectorTypeDefault定義在/art/runtime/gc/collector_type.h

enum CollectorType {
  // No collector selected.
  kCollectorTypeNone,
  //普通Mark-Sweep
  kCollectorTypeMS,
  // 并發Mark-Sweep.
  kCollectorTypeCMS,
  // Semi-space和Mark-Sweep的混合
  kCollectorTypeSS,
  // Generational Semi-space
  kCollectorTypeGSS,
  // Mark compact
  kCollectorTypeMC,
  // Heap trimming collector, doesn't do any actual collecting.
  kCollectorTypeHeapTrim,
  // A (mostly) concurrent copying collector.
  kCollectorTypeCC,
  // Instrumentation critical section fake collector.
  kCollectorTypeInstrumentation,
  // Fake collector for adding or removing application image spaces.
  kCollectorTypeAddRemoveAppImageSpace,
  // A homogeneous space compaction collector used in background transition
  // when both foreground and background collector are CMS.
  kCollectorTypeHomogeneousSpaceCompact,
  // Class linker fake collector.
  kCollectorTypeClassLinker,
};

static constexpr CollectorType kCollectorTypeDefault =
#if ART_DEFAULT_GC_TYPE_IS_CMS
    kCollectorTypeCMS
#elif ART_DEFAULT_GC_TYPE_IS_SS
    kCollectorTypeSS
#elif ART_DEFAULT_GC_TYPE_IS_GSS
    kCollectorTypeGSS
#else
    kCollectorTypeCMS
#error "ART default GC type must be set"
#endif

從代碼中的定義可以看到,如果kUseReadBarrier=true,則垃圾回收算法使用Concurrent-Copying,否則默認算法,默認算法根據編譯宏選擇,沒有特別指定的情況下使用Concurrent Mark-Sweep

二. Heap::Heap()

2.1 構造函數聲明

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,//存儲不可移動對象的space的容量
      const std::string& original_image_file_name,//image文件路徑
      InstructionSet image_instruction_set,//指令集
      CollectorType foreground_collector_type,//前臺回收器類型
      CollectorType background_collector_type,//后臺回收器類型
      space::LargeObjectSpaceType large_object_space_type,//存儲大對象的space類型
      size_t large_object_threshold,//大對象數量的閾值
      size_t parallel_gc_threads,//GC暫停階段用于同時執行GC任務的線程數
      size_t conc_gc_threads,//并行GC的線程數
      bool low_memory_mode,//是否是low memory mode
      size_t long_pause_threshold,//GC造成應用程序暫停的時間閥值,超過則輸出log
      size_t long_gc_threshold,//GC時間閥值,超過則輸出log
      bool ignore_max_footprint,//不對堆的增長進行限制,堆可以增長到它的最大容量
      bool use_tlab,//是否開啟TLAB選項
      bool verify_pre_gc_heap,//是否在開始GC前驗證堆
      bool verify_pre_sweeping_heap,//是否在GC執行清掃前驗證堆
      bool verify_post_gc_heap,//是否在GC完成清掃后驗證堆
      bool verify_pre_gc_rosalloc,//是否在開始GC前驗證RosAllocSpace
      bool verify_pre_sweeping_rosalloc,//是否在GC執行清掃前驗證RosAllocSpace
      bool verify_post_gc_rosalloc,//是否在GC完成清掃后驗證RosAllocSpace
      bool gc_stress_mode,
      bool use_homogeneous_space_compaction,//是否使用homogeneous space compaction來避免OOM
      uint64_t min_interval_homogeneous_space_compaction_by_oom);//兩次OOM引起homogeneous space compaction時間間隔

2.2 構造函數實現

2.2.1 字段初始化

Heap::Heap(...) :
      //space::MallocSpace*,存放不可移動對象
      non_moving_space_(nullptr),
      //kAllocatorTypeROSAlloc space
      rosalloc_space_(nullptr),
      //kAllocatorTypeDlMalloc space
      dlmalloc_space_(nullptr),
      //GC操作的主要space,這個space不是dlmalloc_space_就是rosalloc_space_
      main_space_(nullptr),
      //回收器類型
      collector_type_(kCollectorTypeNone),
      //前臺回收器類型
      foreground_collector_type_(foreground_collector_type),
      //后臺回收器類型
      background_collector_type_(background_collector_type),
      //希望的回收器類型,如果它!=collector_type_, heap trimming daemon會transitions堆
      desired_collector_type_(foreground_collector_type_),
      //Mutex*
      pending_task_lock_(nullptr),
      //GC暫停階段用于同時執行GC任務的線程數
      parallel_gc_threads_(parallel_gc_threads),
      //concurrent gc線程數
      conc_gc_threads_(conc_gc_threads),
      //是否是低內存模式
      low_memory_mode_(low_memory_mode),
      //GC造成應用程序暫停的時間閥值,超過則輸出log
      long_pause_log_threshold_(long_pause_log_threshold),
      //GC時間閥值,超過則輸出log
      long_gc_log_threshold_(long_gc_log_threshold),
      //是否對堆的增長不限制
      ignore_max_footprint_(ignore_max_footprint),
      //zygote space創建時的鎖, Mutex
      zygote_creation_lock_("zygote creation lock", kZygoteCreationLock),
      //space::ZygoteSpace 在zygote space創建之前不會包含大對象
      zygote_space_(nullptr),
      //大對象數量的閾值
      large_object_threshold_(large_object_threshold),
      //跟蹤在JNI critical section中有多少個線程
      disable_thread_flip_count_(0),
      thread_flip_running_(false),
      //正在運行的回收器類型
      collector_type_running_(kCollectorTypeNone),
      //最后一次運行的GC類型
      last_gc_type_(collector::kGcTypeNone),
      //下一次將要運行的GC類型
      next_gc_type_(collector::kGcTypePartial),
      //堆的容量
      capacity_(capacity),
      //堆的增長上限
      growth_limit_(growth_limit),
      //分配對象的上限數,一旦超過著擱置會引起一次GC
      max_allowed_footprint_(initial_size),
      //由registerNativeAllocation請求的一次concurrent GC需要的臨界線, size_t
      native_footprint_gc_watermark_(initial_size),
      //bool, 是否需要在下一次的native allocation中運行finalizers
      native_need_to_run_finalization_(false),
      //當num_bytes_allocated_超過該值后,concurrent GC會啟動
      concurrent_start_bytes_(std::numeric_limits<size_t>::max()),
      //總共釋放的bytes自從heap創建以來
      total_bytes_freed_ever_(0),
      //總共釋放的對象自從heap創建以來
      total_objects_freed_ever_(0),
      //當前分配的bytes數量.每次釋放和分配以后都會更新
      num_bytes_allocated_(0),
      //native分配的bytes數量
      native_bytes_allocated_(0),
      //Mutex
      native_histogram_lock_("Native allocation lock"),
      //Histogram<uint64_t>,native分配的統計圖
      native_allocation_histogram_("Native allocation sizes",
                                   1U,
                                   kNativeAllocationHistogramBuckets),
      //native釋放的統計圖
      native_free_histogram_("Native free sizes", 1U, kNativeAllocationHistogramBuckets),
      num_bytes_freed_revoke_(0),
      verify_missing_card_marks_(false),
      verify_system_weaks_(false),
     //是否在開始GC前驗證堆
      verify_pre_gc_heap_(verify_pre_gc_heap),
      //是否在GC執行清掃前驗證堆
      verify_pre_sweeping_heap_(verify_pre_sweeping_heap),
      //是否在GC完成清掃后驗證堆
      verify_post_gc_heap_(verify_post_gc_heap),
      //是否驗證ModUnionTable
      verify_mod_union_table_(false),
      //是否在開始GC前驗證RosAllocSpace
      verify_pre_gc_rosalloc_(verify_pre_gc_rosalloc),
      //是否在GC執行清掃前驗證RosAllocSpace
      verify_pre_sweeping_rosalloc_(verify_pre_sweeping_rosalloc),
      //是否在GC完成清掃后驗證RosAllocSpace
      verify_post_gc_rosalloc_(verify_post_gc_rosalloc),
      /* For GC a lot mode, we limit the allocations stacks to be kGcAlotInterval allocations. This
       * causes a lot of GC since we do a GC for alloc whenever the stack is full. When heap
       * verification is enabled, we limit the size of allocation stacks to speed up their
       * searching.
       */
      //分配棧最大數量
      max_allocation_stack_size_(kGCALotMode ? kGcAlotAllocationStackSize
          : (kVerifyObjectSupport > kVerifyObjectModeFast) ? kVerifyObjectAllocationStackSize :
          kDefaultAllocationStackSize),
      //當前分配器    
      current_allocator_(kAllocatorTypeDlMalloc),
      //當前不可移動對象分配器
      current_non_moving_allocator_(kAllocatorTypeNonMoving),
      //階躍型指針space
      bump_pointer_space_(nullptr),
      //臨時space,Semispace回收器會將對象拷貝至這里
      temp_space_(nullptr),
      //RegionSpace 有一系列大小相等的區域組成
      region_space_(nullptr),
      //最小空余內存
      min_free_(min_free),
      //最大空余內存
      max_free_(max_free),
      //堆目標利用率
      target_utilization_(target_utilization),
      //前臺堆增長因子
      foreground_heap_growth_multiplier_(foreground_heap_growth_multiplier),
      //mutators暫停等待GC的總共時間
      total_wait_time_(0),
      //VerifyObjectMode, 目前heap verification的狀態
      verify_object_mode_(kVerifyObjectModeDisabled),
      //Compacting GC disable count
      disable_moving_gc_count_(0),
      is_running_on_memory_tool_(Runtime::Current()->IsRunningOnMemoryTool()),
      use_tlab_(use_tlab),
      //homogeneous space compaction時的新main space
      main_space_backup_(nullptr),
      //兩次OOM引起homogeneous space compaction時間間隔
      min_interval_homogeneous_space_compaction_by_oom_(
          min_interval_homogeneous_space_compaction_by_oom),
      //上一次由OOM引起的HomogeneousSpaceCompact的時間
      last_time_homogeneous_space_compaction_by_oom_(NanoTime()),
      //CollectorTransitionTask*
      pending_collector_transition_(nullptr),
      //HeapTrimTask*
      pending_heap_trim_(nullptr),
      //是否使用homogeneous space compaction來避免OOM
      use_homogeneous_space_compaction_for_oom_(use_homogeneous_space_compaction_for_oom),
      //如果當前的回收工作導致一些線程暫停,則該值為true
      running_collection_is_blocking_(false),
      //blocking gc 數量
      blocking_gc_count_(0U),
      //blocking gc總共持續時間
      blocking_gc_time_(0U),
      //GC count rate統計圖最后已更新時間
      last_update_time_gc_count_rate_histograms_(  // Round down by the window duration.
          (NanoTime() / kGcCountRateHistogramWindowDuration) * kGcCountRateHistogramWindowDuration),
      //在上一個window運行的GC數量
      gc_count_last_window_(0U),
      //在上一個window運行的blocking GC數量
      blocking_gc_count_last_window_(0U),
      //每一個window的GC調用統計圖
      gc_count_rate_histogram_("gc count rate histogram", 1U, kGcCountRateMaxBucketCount),
      //每一個window的blocking GC調用統計圖
      blocking_gc_count_rate_histogram_("blocking gc count rate histogram", 1U,
                                        kGcCountRateMaxBucketCount),
      //是否支持allocation tracking
      alloc_tracking_enabled_(false),
      //Mutex*
      backtrace_lock_(nullptr),
      seen_backtrace_count_(0u),
      unique_backtrace_count_(0u),
      gc_disabled_for_shutdown_(false) {

2.2.2 具體創建邏輯

Heap的構造函數的代碼較多,不過整體邏輯比較清晰,整體邏輯可以分為以下幾塊:

  1. 判斷當前是否在zygote進程,如果不在zygote,將background_collector_type_設為和foreground_collector_type_一樣,并檢查傳入的desired_collector_type_collector_type_是否一樣,如果不一樣,則將collector_type_設為desired_collector_type_
  Runtime* const runtime = Runtime::Current();
    //判斷當前是否是zygote模式,如果不是判斷后臺回收器類型是否和前臺回收器相等,不想等,則設為相等
    const bool is_zygote = runtime->IsZygote();
    if (!is_zygote) {
        if (background_collector_type_ != foreground_collector_type_) {
            ...
            background_collector_type_ = foreground_collector_type_;
        }
    }
    //檢查collector_type_是否和desired_collector_type_相等,不等的話將collector_type_置為desired_collector_type_
    ChangeCollector(desired_collector_type_);
  1. 創建兩個HeapBitmap(live_bitmap_:用來記錄上次GC之后還存活的對象;mark_bitmap_:用來記錄當前GC中還存活的對象)
live_bitmap_.reset(new accounting::HeapBitmap(this));
mark_bitmap_.reset(new accounting::HeapBitmap(this));
  1. 如果foreground_collector_type_是Concurrent-Copying,設置requested_alloc_space_begin即alloc space的起始地址為(如果前臺回收器是CC則是300MB-non_moving_space_capacity,否則是nullptr)
if (foreground_collector_type_ == kCollectorTypeCC) {
    ...  
    requested_alloc_space_begin = reinterpret_cast<uint8_t*>(300 * MB) - non_moving_space_capacity;
}
  1. 根據傳入的image文件路徑(/system/framework/boot.art)創建ImageSpace,在ImageSpace后面緊跟的是/system/framework/boot.oat,如果創建成功,將requested_alloc_space_begin指向boot.oat地址的末尾;如果創建ImageSpace失敗,刪除已加載的Space,將requested_alloc_space_begin指回原來的(300MB-non_moving_space_capacity)
//創建ImageSpace, image_file_name是/system/framework/boot.art
if (!image_file_name.empty()) {
    std::vector<std::string> image_file_names;
    image_file_names.push_back(image_file_name);
    std::vector<space::Space*> added_image_spaces;
    uint8_t* const original_requested_alloc_space_begin = requested_alloc_space_begin;
    for (size_t index = 0; index < image_file_names.size(); ++index) {
        std::string& image_name = image_file_names[index];///system/framework/boot.art
        std::string error_msg;
        //創建boot_image_space
        space::ImageSpace* boot_image_space = space::ImageSpace::CreateBootImage(
                image_name.c_str(),
                image_instruction_set,
                index > 0,
                &error_msg);
        //創建boot_image_space成功
        if (boot_image_space != nullptr) {
            /* 根據boot_image_space是否時連續空間,將boot_image_space添加到對應的Space列表,并在live_bitmap_和mark_bitmap_中添加對應的位圖 */
            AddSpace(boot_image_space);
            added_image_spaces.push_back(boot_image_space);
            //Oat文件即boot.oat緊跟在boot_image_space末尾
            uint8_t* oat_file_end_addr = boot_image_space->GetImageHeader().GetOatFileEnd();
            ...
            //將boot.oat的地址按頁大小(pageSize)對齊
            requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
            boot_image_spaces_.push_back(boot_image_space);

            if (index == 0) {
              //如果是第一塊Space,檢查是否還有其他的oat文件需要加載
              const OatFile* boot_oat_file = boot_image_space->GetOatFile();
              if (boot_oat_file == nullptr) {
                continue;
              }
              //如果還有其他的oat文件,根據OatHeader獲取boot_classpath,再根據boot_classpath生成
              //oat文件完整路徑,將完整路徑添加進image文件列表,從而可以在下次循環中加載
              const OatHeader& boot_oat_header = boot_oat_file->GetOatHeader();
              const char* boot_classpath =
                  boot_oat_header.GetStoreValueByKey(OatHeader::kBootClassPathKey);
              if (boot_classpath == nullptr) {
                continue;
              }
              space::ImageSpace::CreateMultiImageLocations(image_file_name,
                                                                 boot_classpath,
                                                                 &image_file_names);
            }
        } else {
            //創建ImageSpace失敗, 刪除已加載的Space
            for (space::Space* loaded_space : added_image_spaces) {
              RemoveSpace(loaded_space);
              delete loaded_space;
            }
            boot_image_spaces_.clear();
            requested_alloc_space_begin = original_requested_alloc_space_begin;
            break;
        }
    }
}
  1. 判斷是否支持Homogeneous-Space-Compact.當background_collector_type_是Homogeneous-Space-Compact或者foreground_collector_type_不是GSS(Generational Semi-Space)CC(Concurrent-Copying)時,支持Homogeneous-Space-Compact
if (foreground_collector_type_ == kCollectorTypeGSS ||
            foreground_collector_type_ == kCollectorTypeCC) {
      use_homogeneous_space_compaction_for_oom_ = false;
}
//如果后臺回收器是homogeneous space compact或者前臺回收器不是GSS和CC時,支持homogeneous space compact
bool support_homogeneous_space_compaction =
      background_collector_type_ == gc::kCollectorTypeHomogeneousSpaceCompact ||
      use_homogeneous_space_compaction_for_oom_;
  1. 判斷是否給Non-Moving Space獨立的地址.只要以下滿足四個條件中的一項就會給Non-Moving Space獨立地址(處于Zygote;支持Homogeneous-Space-Compact(foreground_collector_type_不是GSS或者不是CC);foreground_collector_type_可以移動對象;background_collector_type_可以移動對象), 之后再排除foreground_collector_type_是GSS的情況,即前臺回收器是GSS時,不給Non-Moving Space獨立地址
//如果當前處于Zygote模式或者支持homogeneous space compact或者前臺回收器是可以移動對象的或者后臺回收器也可以移動對象時
//給non_moving_space一個獨立的地址
bool separate_non_moving_space = is_zygote ||
          support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) ||
          IsMovingGc(background_collector_type_);
//再次檢查前臺進程是否是GSS,如果是,則不給non_moving_space_一個獨立的地址
if (foreground_collector_type_ == kCollectorTypeGSS) {
    separate_non_moving_space = false;
}

只要傳入的type是SS,GSS,CC,MC,Homogeneous-Space-Compact其中一個時,IsMovingGc返回的都是true

  1. 創建兩個內存映射MemMap
std::unique_ptr<MemMap> main_mem_map_1;
std::unique_ptr<MemMap> main_mem_map_2;
  1. 如果之前創建ImageSpace失敗同時foreground_collector_type_MarkSweep而且此時的Runtime由dex2oat創建即處于dex2oat進程中時,將requested_alloc_space_begin指向kAllocSpaceBeginForDeterministicAoT
// 如果前臺回收器是MS(MarkSweep)且requested_alloc_space_begin
// 是null(即之前ImageSpace創建失敗)同時當前是dex2oat程序
// 將requested_alloc_space_begin設為kAllocSpaceBeginForDeterministicAoT
if (foreground_collector_type_ == kCollectorTypeMS &&
            requested_alloc_space_begin == nullptr &&
            Runtime::Current()->IsAotCompiler()) {
    requested_alloc_space_begin = reinterpret_cast<uint8_t*>(kAllocSpaceBeginForDeterministicAoT);
}
  1. 初始化request_begin.如果Non-Moving Space有獨立地址,根據當前是否是zygote確定Non-Moving Space的名字,之后創建一塊匿名內存映射,由non_moving_space_mem_map指向,non_moving_space_mem_map緊跟在requested_alloc_space_begin后面,如果ImageSpace創建成功,就是緊跟在ImageSpace+boot.oat后面,否則緊跟在kAllocSpaceBeginForDeterministicAoT后面,最后設置request_begin為300MB,即其他Space的起始地址為300MB
uint8_t* request_begin = requested_alloc_space_begin;
if (request_begin != nullptr && separate_non_moving_space) {
    request_begin += non_moving_space_capacity;
}
std::string error_str;
std::unique_ptr<MemMap> non_moving_space_mem_map;
//如果確定給non moving space一塊獨立的地址
if (separate_non_moving_space) {
    ScopedTrace trace2("Create separate non moving space");
    // 如果當前正在Zygote當中,將non moving space設為zygote space
    const char* space_name = is_zygote ? kZygoteSpaceName: kNonMovingSpaceName;
    //創建匿名內存映射
    //non moving sapce緊跟在requested_alloc_space_begin后面(即如果ImageSpace創建成功,緊跟在ImageSpace + boo.oat后面)
    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));
    ...
    // 如果要給non moving space一個獨立的地址, 將其他Space的起始地址設為300MB,由request_begin指向
    request_begin = reinterpret_cast<uint8_t*>(300 * MB);
}
  1. 如果foreground_collector_type_不是CC,初始化之前創造的main_mem_map_1,這塊內存的作用是作為MarkSweepMain Space或者Compact GCFrom-Bump-Space.當Non-Moving Space有獨立地址且當前不處于Zygote時,緊跟在300MB后面創建匿名內存映射;否則緊跟在ImageSpace+boot.oat后面創建匿名內存映射
//如果前臺回收器不是CC,創建第一塊匿名共享內存,由main_mem_map_1指向,這塊內存的作用是作為Compact GC的From Bump Space或者
//MarkSweep的Main Space
if (foreground_collector_type_ != kCollectorTypeCC) {
      ScopedTrace trace2("Create main mem map");
      if (separate_non_moving_space || !is_zygote) {
          //如果non moving space有獨立地址或者當前不是zygote,則main_mem_map_1緊跟在  request_begin后面,即300MB后面
          //名字是main space
          main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0],
                                                            request_begin,
                                                            capacity_,
                                                            &error_str));
      } else {
          //如果non-moving space有獨立地址且當前處于zygote或者non-moving space沒有獨立地址,
          //則main space必須緊跟在ImageSpace后面,這樣zygote space就會臨近ImageSpace
          main_mem_map_1.reset(MemMap::MapAnonymous(kMemMapSpaceName[0], request_begin, capacity_,
                                                    PROT_READ | PROT_WRITE, true, false,
                                                    &error_str));
      }
      ...
}
  1. 如果支持Homogeneous-Space-Compact或者background_collector_type_foreground_collector_type_其中一個是SS時,創建第二塊匿名內存映射main_mem_map_2
//如果支持homogeneous space compact或者后臺回收器和前臺回收器中有一個為為SS(Semi Space)時,創建第二塊匿名共享內存
//由main_mem_map_2指向
if (support_homogeneous_space_compaction ||
        background_collector_type_ == kCollectorTypeSS ||
        foreground_collector_type_ == kCollectorTypeSS) {
      ScopedTrace trace2("Create main mem map 2");
      main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(),
                                                            capacity_, &error_str));
      ...
}
  1. 如果Non-Moving Space有獨立地址,則之前已經創建了匿名內存映射non_moving_space_mem_map,現在將這塊內存封裝成DlMallocSpace,由non-moving_space指向,并將這塊Space添加至Space列表中
//如果non moving space有獨立的地址時,將non_moving_space_mem_map封裝成Non-Moving Space(space::MallocSpace)
if (separate_non_moving_space) {
      ScopedTrace trace2("Add non moving space");
      //Non-Moving Space必須是dlmalloc,因為目前并不支持多個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大小限制
      non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
      ...
      //將non_moving_space_添加至space列表中
      AddSpace(non_moving_space_);
}
  1. 根據條件處理之前創建的另外兩塊匿名內存映射main_mem_map_1main_mem_map_2.因為在之前的邏輯中,當foreground_collector_type_是CC時,并沒有創建main_mem_map_1匿名內存映射,所以如果foreground_collector_type_恰好是CC時,緊跟request_begin(如果Non-Moving Space有獨立地址,則是300MB,否則是ImageSpace+boot.oat)創建一個RegionSpace,由region_space_指向; 如果foreground_collector_type_不是CC時,也要分兩種情況:(1)foreground_collector_type_SS,MC,Homogeneous-Space-Compact中的一個;(2)foreground_collector_type_MarkSweep, Compact MarkSweep或者GSS. 對于第一種情況來說,將main_mem_map_1封裝成BumpPointerSpace1并添加至space列表,由bump_pointer_space_指向,將main_mem_map_2封裝成另一塊BumpPointerSpace2同樣添加至space列表,由temp_space_指向;對于第二種情況,首先將main_mem_map_1封裝成MainSpace同時添加至space列表,之后如果Non-Moving Space沒有獨立地址,則將non_moving_space_指向MainSpace,即MainSpace和Non-Moving Space共用同一塊內存,接著判斷如果foreground_collector_type_是GSS時,調用BumpPointerSpace::Craete直接創建BumpPointerSpace1(bump_pointer_space_)和BumpPointerSpace2(temp_space_)并依次添加至space列表;如果foreground_collector_type_不是GSS時,即MarkSweepCompact MarkSweep,且main_mem_map_2不為空時(如果支持HomogeneousSpaceCompact),將main_mem_map_2封裝成Backup Space,并添加至space列表
if (foreground_collector_type_ == kCollectorTypeCC) {
      // 如果前臺回收器是CC(Concurrent Copying),創建RegionSpace,并將RegionSpace添加至space列表
      region_space_ = space::RegionSpace::Create("Region space", capacity_ * 2, request_begin);
      AddSpace(region_space_);
} else if (IsMovingGc(foreground_collector_type_) &&
          foreground_collector_type_ != kCollectorTypeGSS) {
      //如果前臺回收器是除了GSS(Generational Semi-Space)以外的Compact GC,將main_mem_map_1封裝成BumpPointerSpace
      //并將bump_pointer_space_添加至space列表
      // 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_);
      //將main_mem_map_2封裝成第二塊BumpPointerSpace,由temp_space_指向,同時將temp_space_添加至space列表
      temp_space_ = space::BumpPointerSpace::CreateFromMemMap("Bump pointer space 2",
                                                                    main_mem_map_2.release());
      ...
      AddSpace(temp_space_);
      ...
} else {
      //如果前臺回收器不是Compact GC即MarkSweep或者是GSS,則在main_mem_map_1創建Main Space,并將Main Space添加至space列表
      CreateMainMallocSpace(main_mem_map_1.release(), initial_size, growth_limit_, capacity_);
      ...
      AddSpace(main_space_);
      if (!separate_non_moving_space) {
          //如果Non-Moving Space沒有獨立地址,則將non_moving_space_指向main_space_,即Non-Moving Space和Main Space是同一塊Space
          non_moving_space_ = main_space_;
          ...
      }
      if (foreground_collector_type_ == kCollectorTypeGSS) {
          ....
          //如果前臺回收器是GSS, 并創建BumpPointerSpace,由bump_pointer_space_指向
          //同時將bump_pointer_space_添加至space列表
          main_mem_map_2.release();
          bump_pointer_space_ = space::BumpPointerSpace::Create("Bump pointer space 1",
                                                              kGSSBumpPointerSpaceCapacity, nullptr);
          ...
          AddSpace(bump_pointer_space_);
          //創建第二塊BumpPointerSpace,由temp_space_指向,并將temp_space_添加至space列表
          temp_space_ = space::BumpPointerSpace::Create("Bump pointer space 2",
                                                            kGSSBumpPointerSpaceCapacity, nullptr);
          ...
          AddSpace(temp_space_);
      }  else if (main_mem_map_2.get() != nullptr) {
          //此時前臺回收器根據排除法只剩MarkSweep了,將main_mem_map_2封裝成Backup Space,由main_space_backup_指向
          //同時將main_space_backup_添加至space列表,如果kUseRosAlloc為true,main_space_backup_為RosAllocSpace,否則為DlMallocSpace
          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));
          ...
          AddSpace(main_space_backup_.get());
        }
}
  1. 創建大對象存儲空間.
// 創建LargeObjectSpace(大對象存儲空間)
if (large_object_space_type == space::LargeObjectSpaceType::kFreeList) {
      //如果LargeObjectSpace類型是FreeList,創建FreeList類型的LargeObjectSpace
      large_object_space_ = space::FreeListSpace::Create("free list large object space", nullptr,
                                                               capacity_);
      ...
} else if (large_object_space_type == space::LargeObjectSpaceType::kMap) {
      //創建相互獨立的內存快組成的LargeObjectSpace
      large_object_space_ = space::LargeObjectMapSpace::Create("mem map large object space");
      ...
} else {
      large_object_threshold_ = std::numeric_limits<size_t>::max();
      large_object_space_ = nullptr;
}
//如果LargeObjectSpace不為空,則添加至Space列表
if (large_object_space_ != nullptr) {
      AddSpace(large_object_space_);
}
  1. 如果foreground_collector_type_是MarkSweep或Compact MarkSweep且創建了Backup Space時,由于Backup Space占用的額外的空間會降低GC速度,所以移除Backup Space;之后創建CardTable(Card Table是為了記錄在垃圾收集過程中對象的引用情況的), ModUnionTable(來記錄ImageSpace對ZygoteSpace引用情況的ModUnionTable), RememberSet(用來記錄Non-moving Space對其他Space引用情況的RememberedSet, GSS時不會創建,CC, SS, MC, HomogeneousSpaceCompact時根據collector::SemiSpace::kUseRememberedSet == true判斷, MS,CMS時根據Non-Moving Space有沒有獨立地址加collector::SemiSpace::kUseRememberedSet == true判斷)
//獲取連續空間的起始地址和結束地址
uint8_t* heap_begin = continuous_spaces_.front()->Begin();
uint8_t* heap_end = continuous_spaces_.back()->Limit();
size_t heap_capacity = heap_end - heap_begin;
//移除main_space_backup_,此時foreground_collector_type_是MarkSweep
//因為Backup Space的額外的未使用的空間降低了GC速度
if (main_space_backup_.get() != nullptr) {
       RemoveSpace(main_space_backup_.get());
}
...
// 創建card table,因為不知道在low_4gb模式下,app image會在何處定位,
// 所以card table將會從64KB開始覆蓋整個4GB的低地址,64KB以前的地址預留給kernel
static constexpr size_t kMinHeapAddress = 4 * KB;
card_table_.reset(accounting::CardTable::Create(reinterpret_cast<uint8_t*>(kMinHeapAddress), 4 * GB - kMinHeapAddress));
....
//如果前臺回收器是CC(Concurrent Copying)同時kUseTableLookupReadBarrier=true,創建ReadBarrierTable
if (foreground_collector_type_ == kCollectorTypeCC && kUseTableLookupReadBarrier) {
      rb_table_.reset(new accounting::ReadBarrierTable());
    ...
}
if (HasBootImageSpace()) {
    // 如果有ImageSpace,則創建用來記錄ImageSpace對ZygoteSpace引用情況的ModUnionTable
    for (space::ImageSpace* image_space : GetBootImageSpaces()) {
        accounting::ModUnionTable* mod_union_table = new     accounting::ModUnionTableToZygoteAllocspace(
              "Image mod-union table", this, image_space);
          ...
        AddModUnionTable(mod_union_table);
    }
}
//如果Non-moving Space有獨立地址而且kUseRememberedSet=true,
//創建用來記錄Non-moving Space對其他Space引用情況的RememberedSet
if (collector::SemiSpace::kUseRememberedSet && non_moving_space_ != main_space_) {
        accounting::RememberedSet* non_moving_space_rem_set =
            new accounting::RememberedSet("Non-moving space remembered set", this, non_moving_space_);
        ...
        AddRememberedSet(non_moving_space_rem_set);
}
  1. 創建Mark-Stack,Allocation-Stack,Live-Stack;創建之后GC需要用到的的鎖;創建TaskProcessor,ReferenceProcessor;如果前后臺回收器有一個是CMS,則創建一組包含三個支持并發的Collector:MarkSweep, PartialMarkSweep, StickyMarkSweep回收器; 如果前后臺回收器有一個是MS,則創建一組包含三個不支持并發的Collector:MarkSweep, PartialMarkSweep, StickyMarkSweep回收器;之后再根據條件創建Semi-Space Collector(SSGSS時創建),Concurrent-Copying Collector(CC時創建),Mark Compact Collector(MS,CMSshichu)
// TODO: Count objects in the image space here?
num_bytes_allocated_.StoreRelaxed(0);
// 創建Mark-Stack, Allocation-Stack, Live-Stack
mark_stack_.reset(accounting::ObjectStack::Create("mark stack", kDefaultMarkStackSize, kDefaultMarkStackSize));
const size_t alloc_stack_capacity = max_allocation_stack_size_ + kAllocationStackReserveSize;
allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack", max_allocation_stack_size_, alloc_stack_capacity));
live_stack_.reset(accounting::ObjectStack::Create("live stack", max_allocation_stack_size_, alloc_stack_capacity));
// 創建gc_complete_lock_,thread_flip_lock_
gc_complete_lock_ = new Mutex("GC complete lock");
gc_complete_cond_.reset(new ConditionVariable("GC complete condition variable",*gc_complete_lock_));
thread_flip_lock_ = new Mutex("GC thread flip lock");
thread_flip_cond_.reset(new ConditionVariable("GC thread flip condition variable",*thread_flip_lock_));
//創建TaskProcessor, ReferenceProcessor, pending_task_lock_
task_processor_.reset(new TaskProcessor());
reference_processor_.reset(new ReferenceProcessor());
pending_task_lock_ = new Mutex("Pending task lock");
if (ignore_max_footprint_) {
      //如果不限制堆的增長,則將堆的最大限制數設為最大
      SetIdealFootprint(std::numeric_limits<size_t>::max());
      //將concurrent gc的啟動值也設為最大,即只有堆達到最大時,才開啟concurrent gc
      concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
}
...
// 如果前后臺回收器有一個是CMS,則創建一組包含三個支持并發的Collector:MarkSweep, PartialMarkSweep, StickyMarkSweep回收器
// 如果前后臺回收器有一個是MS,則創建一組包含三個不支持并發的Collector:MarkSweep, PartialMarkSweep, StickyMarkSweep回收器
for (size_t i = 0; i < 2; ++i) {
      const bool concurrent = i != 0;
      if ((MayUseCollector(kCollectorTypeCMS) && concurrent) ||
                (MayUseCollector(kCollectorTypeMS) && !concurrent)) {
          garbage_collectors_.push_back(new collector::MarkSweep(this, concurrent));
          garbage_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
          garbage_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
      }
}
if (kMovingCollector) {//kMovingCollector=true
      if (MayUseCollector(kCollectorTypeSS) || MayUseCollector(kCollectorTypeGSS) ||
                  MayUseCollector(kCollectorTypeHomogeneousSpaceCompact) ||
                  use_homogeneous_space_compaction_for_oom_) {
        //如果前后臺回收器中某一個是SS,GSS,HomogeneousSpaceCompact三者其中一個或者
        //使用homogeneous space compaction來避免OOM時,再創鍵一個Semi-Space Collector
        const bool generational = foreground_collector_type_ == kCollectorTypeGSS;
        semi_space_collector_ = new collector::SemiSpace(this, generational,
                                                               generational ? "generational" : "");
        garbage_collectors_.push_back(semi_space_collector_);
      }
      if (MayUseCollector(kCollectorTypeCC)) {
        //如果前后臺回收器中某一個是CC,再創建一個ConcurrentCopying Collector
        concurrent_copying_collector_ = new collector::ConcurrentCopying(this);
        garbage_collectors_.push_back(concurrent_copying_collector_);
      }
      if (MayUseCollector(kCollectorTypeMC)) {
        //如果前后臺回收器中某一個是MarkCompact,再創建一個MarkCompact Collector
        mark_compact_collector_ = new collector::MarkCompact(this);
        garbage_collectors_.push_back(mark_compact_collector_);
      }
}
  1. 如果有ImageSpace同時Non-Moving Space不為空同時滿足三個條件(處于zygote,Non-Moving Space有獨立地址,前臺回收器是GSS)中的一個時,檢查ImageSpace和Non-Moving Space之間沒有內存空隙
if (!GetBootImageSpaces().empty() && non_moving_space_ != nullptr &&
            (is_zygote || separate_non_moving_space || foreground_collector_type_ == kCollectorTypeGSS)) {
      //如果有ImageSpace同時Non-Moving Space不為空同時滿足三個條件
      //(處于zygote,Non-Moving Space有獨立地址,前臺回收器是GSS)中的一個時,
      //檢查ImageSpace和Non-Moving Space只見沒有內存空隙
      space::ImageSpace* first_space = nullptr;
      for (space::ImageSpace* space : boot_image_spaces_) {
        if (first_space == nullptr || space->Begin() < first_space->Begin()) {
          first_space = space;
        }
      }
      bool no_gap = MemMap::CheckNoGaps(first_space->GetMemMap(), non_moving_space_->GetMemMap());
      if (!no_gap) {
        PrintFileToLog("/proc/self/maps", LogSeverity::ERROR);
        MemMap::DumpMaps(LOG(ERROR), true);
        ...
      }
  }
instrumentation::Instrumentation* const instrumentation = runtime->GetInstrumentation();
if (gc_stress_mode_) {
      backtrace_lock_ = new Mutex("GC complete lock");
}
if (is_running_on_memory_tool_ || gc_stress_mode_) {
      instrumentation->InstrumentQuickAllocEntryPoints();
}

三. 總結

3.1 前臺回收器是ConcurrentCopying

從代碼邏輯看,如果foreground_collector_type_=kCollectorTypeCC時Heap的創建流程要跟其他回收器類型的創建流程不太相同:

  1. requested_alloc_space_begin = 300MB - non_moving_space_capacity
  2. 創建ImageSpace(只要image文件不為空,都會創建),如果創建成功,requested_alloc_space_begin=ImageSpace+boo.oat

這一點所有回收器類型都一樣,不同的是,如果創建失敗,requested_alloc_space_begin = 300MB - non_moving_space_capacity, 其他回收器類型則是requested_alloc_space_begin = nullptr

  1. 如果background_collector_type_ != kCollectorTypeHomogeneousSpaceCompact,則不支持Homogeneous-Space-Compact
  2. 由于是CC回收器,所以必然會給Non-Moving Space獨立的地址
  3. 由于是CC回收器,所以即使ImageSpace創建失敗,requested_alloc_space_begin也不會為nullptr,又因為Non-Moving Space有獨立的地址,所以最后request_begin=requested_alloc_space_begin + non_moving_space_capacity

如果ImageSpace創建成功,request_begin=ImageSpace+boot.oat+non_moving_space_capacity;如果創建失敗,request_begin = 300MB-non_moving_space_capacity+non_moving_space_capacity->request_begin=300MB

  1. 緊跟著requested_alloc_space_begin創建用于Non-Moving Space的匿名內存映射non_moving_space_mem_map, 將request_begin固定在300MB的地址(request_begin=reinterpret_cast<uint8_t*>(300*MB));之后將匿名內存映射封裝成Non-Moving Space,如果在Zygote中,就叫ZygoteSpace,否則叫Non-Moving Space
  2. 由于是CC回收器,所以不會創建兩塊匿名內存main_mem_map_1,main_mem_map_2,而是緊跟著在request_begin后(即300MB,因為之前已經將request_begin固定在這個地址)直接創建RegionSpace
  3. 創建LargeObjectSpace
  4. 如果kUseTableLookupReadBarrier=true,創建ReadBarrierTable
  5. 創建CardTable,ModUnionTable(如果ImageSpace創建成功),如果collector::SemiSpace::kUseRememberedSet == true創建RememberedSet;創建allocation_stack_,mark_stack_,live_stack_;創建鎖;創建TaskProcessor,ReferenceProcessor
  6. 由于是CC回收器,創建collector::ConcurrentCopying并添加至garbage_collectors_
  7. 如果ImageSpace創建成功,且Non-Moving Space不為空,檢查ImageSpace和Non-Moving Space之間有沒有內存間隙

因為是CC,所以Non-Moving Space必然有獨立地址,所以只需要判斷ImageSpace創建成功和Non-Moving Space不為空

3.2 前臺回收器是GSS

GSS(Generational Semi-Space)是另一個較為特殊的回收器類型

  1. requested_alloc_space_begin=nullptr
  2. 創建ImageSpace,如果成功,requested_alloc_space_begin=ImageSpace+boot.oat,如果創建失敗,requested_alloc_space_begin=nullptr
  3. 如果background_collector_type_ != kCollectorTypeHomogeneousSpaceCompact,則肯定不支持Homogeneous-Space-Compact
  4. 由于是GSS回收器,所以不會給Non-Moving Space獨立的地址(這一點很重要,即不會創建Non-Moving Space的匿名內存映射)
  5. 如果ImageSpace創建失敗,則request_begin=requested_alloc_space_begin=nullptr;如果創建成功,則request_begin=reuqest_alloc_space_begin=ImageSpace+boo.oat
  6. 由于是GSS回收器,那么Non-Moving Space不會有獨立地址,如果此時處于Zygote中,則緊跟ImageSpace+boo.oat創建匿名內存映射main_mem_map_1(因為Non-Moving Space沒有獨立地址,所以不會將request_begin固定在300MB,又因為如果ImageSpace創建成功此時request_begin=ImageSpace+boot.oat)
  7. 如果background_collector_type_ == kCollectorTypeHomogeneousSpaceCompact,則會緊跟著main_mem_map_1再創建第二塊匿名內存映射main_mem_map_2,否則不會創建main_mem_map_2
  8. main_mem_map_1封裝成Main Space,由于是GSS回收器,所以將non_moving_space_也指向Main Space
  9. 由于是GSS回收器,調用space::BumpPointerSpace::Create直接創建BumpPointerSpace1BumpPointerSpace2
  10. 創建LargeObjectSpace
  11. 創建CardTable,ModUnionTable(如果ImageSpace創建成功),由于是GSS回收器,所以non_moving_space_ == main_space_,所以不會創建RememberedSet;創建allocation_stack_,mark_stack_,live_stack_;創建鎖;創建TaskProcessor,ReferenceProcessor
  12. 由于是GSS,所以創建collector::SemiSpace,其中generational_ = true
  13. 如果ImageSpace創建成功,且MainSpace不為空,檢查ImageSpace和Non-Moving Space之間有沒有內存間隙

因為是GSS,所以non_moving_space_指向MainSpace,所以只需要判斷ImageSpace創建成功和Non-Moving Space不為空

3.3 Moving GC(Semi-Space, MarkCompact, HomogeneousSpaceCompact)

  1. requested_alloc_space_begin=nullptr
  2. 創建ImageSpace,如果成功,requested_alloc_space_begin=ImageSpace+boot.oat,如果創建失敗,requested_alloc_space_begin=nullptr
  3. 由于不是GSSCC,所以只要傳入的use_homogeneous_space_compaction==true或者background_collector_type_ == kCollectorTypeHomogeneousSpaceCompact時會支持Homogeneous-Space-Compact
  4. Non-Moving必然有獨立的地址
  5. 如果ImageSpace創建成功,request_begin = requested_alloc_space_begin + non_moving_space_capacity,否則request_begin=nullptr
  6. 創建Non-Moving Space使用的匿名內存映射non_moving_space_mem_map,將request_begin固定在300MB的地址(request_begin=reinterpret_cast<uint8_t*>(300*MB))
  7. 緊跟request_begin創建匿名內存映射main_mem_map_1
  8. 如果支持Homogeneous-Space-Compact或者前后臺回收器有一個是Semi-Space,則緊跟main_mem_map_1創建第二塊匿名內存映射main_mem_map_2
  9. non_moving_space_mem_map封裝成Non-Moving Space,由non_moving_space_指向
  10. main_mem_map_1封裝成BumpPointerSpace1,將main_mem_map_2封裝成BumpPointerSpace2
  11. 創建LargeObjectSpace
  12. 創建CardTable,ModUnionTable(如果ImageSpace創建成功),如果collector::SemiSpace::kUseRememberedSet == true創建RememberedSet;創建allocation_stack_,mark_stack_,live_stack_;創建鎖;創建TaskProcessor,ReferenceProcessor
  13. 如果前后臺回收器中有一個是SSHomogeneous-Space-Compact,創建collector::SemiSpace;如果前后臺回收器有一個是MarkCompact,則創建collector::MarkCompact
  14. 如果ImageSpace創建成功,且Non-Moving Space不為空,檢查ImageSpace和Non-Moving Space之間有沒有內存間隙

因為Non-Moving必然有獨立的地址,所以只需要判斷ImageSpace創建成功和Non-Moving Space不為空

3.4 前臺回收器MarkSweep或Concurrent MarkSweep

  1. requested_alloc_space_begin=nullptr
  2. 創建ImageSpace,如果成功,requested_alloc_space_begin=ImageSpace+boot.oat,如果創建失敗,requested_alloc_space_begin=nullptr
  3. 由于不是GSSCC,所以只要傳入的use_homogeneous_space_compaction=true或者background_collector_type_ == kCollectorTypeHomogeneousSpaceCompact時會支持Homogeneous-Space-Compact
  4. 只要當前處于Zygote當中,則Non-Moving Space必然有獨立地址,否則得看是否支持Homogeneous-Space-Compact,支持的話,就有獨立地址,不支持就沒有
  5. 如果ImageSpace創建失敗且foreground_collector_type_=kCollectorTypeMS同時當前處于dex2oat,requested_alloc_space_begin=kAllocSpaceBeginForDeterministicAoT
  6. 如果ImageSpace創建成功且如果Non-Moving Space有獨立地址的話,創建Non-Moving Space要用到的匿名內存映射non_moving_space_mem_map,將request_begin固定在300MB的地址(request_begin=reinterpret_cast<uint8_t*>(300*MB))
  7. 如果Non-Moving Space有獨立地址或者當前不在Zygote中,緊跟著request_begin(300MB)創建匿名內存映射main_mem_map_1;如果Non-Moving Space沒有獨立地址同時處于Zygote中,則緊跟著ImageSpace_boot.oat創建匿名內存映射main_mem_map_1
  8. 如果支持Homogeneous-Space-Compact,緊跟著main_mem_map_1創建第二塊匿名內存映射main_mem_map_2,否則不創建main_mem_map_2
  9. 如果Non-Moving Space有獨立地址,將non_moving_space_mem_map封裝成Non-Moving Space
  10. main_mem_map_1封裝成Main Space,如果Non-Moving Space沒有獨立地址,則將non_moving_space_也指向MainSpace
  11. 如果之前創建了main_mem_map_2,則將main_mem_map_2封裝成Main Backup Space
  12. 創建LargeObjectSpace
  13. 移除Main Backup Space
  14. 創建CardTable,ModUnionTable(如果ImageSpace創建成功),如果Non-Moving Space有獨立地址,創建RememberedSet,否則不創建;創建allocation_stack_,mark_stack_,live_stack_;創建鎖;創建TaskProcessor,ReferenceProcessor
  15. 創建一組回收器,里面有三個回收器分別是MarkSweep, PartialMarkSweep, StickyMarkSweep,如果是Concurrent Mark Compact,則這一組回收器是支持并行GC的;如果是MarkSweep,則這一組不支持并行GC
  16. 如果ImageSpace創建成功且Non-Moving Space不為空同時滿足:處于Zygote或者Non-Moving Space有獨立地址時,檢查ImageSpace和Non-Moving Space之間有沒有內存間隙

因為Non-Moving Space有沒有獨立地址不確定,需要視條件而定

四. 參考資料

  1. ART運行時垃圾收集機制簡要介紹和學習計劃
  2. Debugging ART Garbage Collection
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內容