zoukankan      html  css  js  c++  java
  • ART的堆内存布局

    ART堆内存由若干个space组成,map表中的space的布局如下:

        00000000'12c00000-00000000'12e68fff rw-         0    269000  /dev/ashmem/dalvik-main space (deleted)
        00000000'12e69000-00000000'22bfffff ---    269000   fd97000  /dev/ashmem/dalvik-main space (deleted)
        00000000'32c00000-00000000'32c00fff rw-         0      1000  /dev/ashmem/dalvik-main space 1 (deleted)
        00000000'32c01000-00000000'42bfffff ---      1000   ffff000  /dev/ashmem/dalvik-main space 1 (deleted)
        00000000'6f064000-00000000'6feb5fff rw-         0    e52000  /data/dalvik-cache/arm64/system@framework@boot.art
        00000000'6feb6000-00000000'7232efff r--         0   2479000  /data/dalvik-cache/arm64/system@framework@boot.oat
        00000000'7232f000-00000000'74825fff r-x   2479000    a36000  /data/dalvik-cache/arm64/system@framework@boot.oat
        00000000'74826000-00000000'74826fff rw-   4970000      1000  /data/dalvik-cache/arm64/system@framework@boot.oat
        00000000'74827000-00000000'749a6fff rw-         0    180000  /dev/ashmem/dalvik-zygote space (deleted)
        00000000'749a7000-00000000'749a7fff rw-         0      1000  /dev/ashmem/dalvik-non moving space (deleted)
        00000000'749a8000-00000000'749b9fff rw-      1000     12000  /dev/ashmem/dalvik-non moving space (deleted)
        00000000'749ba000-00000000'78027fff ---     13000   366e000  /dev/ashmem/dalvik-non moving space (deleted)
        00000000'78028000-00000000'78826fff rw-   3681000    7ff000  /dev/ashmem/dalvik-non moving space (deleted)
        00000000'78827000-00000000'98826fff rw-         0  20000000  /dev/ashmem/dalvik-free list large object space (deleted)

    非等比例图如下:

    如上图,可分为如下几种space:main space、image space、zygote space、non moving space、large object space。

    这些space是在art::gc::Heap类的构造函数中被创建出来,其调用流程如下:

    main()@frameworks/base/cmds/app_process/app_main.cpp
        android::AndroidRuntime::startVm()@frameworks/base/core/jni/AndroidRuntime.cpp
            JNI_CreateJavaVM()@art/runtime/java_vm_ext.cc
                art::Runtime::Create()@art/runtime/runtime.cc
                    art::Runtime::Init()@art/runtime/runtime.cc
                        art::gc::Heap::Heap()@art/runtime/gc/heap.cc

    构建space的代码如下:

    Heap::Heap(...) {
      ...
      if (!image_file_name.empty()) {
        std::string error_msg;
        //加载boot.art和boot.oat,构建image space
        auto* image_space = space::ImageSpace::Create(image_file_name.c_str(), image_instruction_set, &error_msg);
        if (image_space != nullptr) {
          AddSpace(image_space);
          uint8_t* oat_file_end_addr = image_space->GetImageHeader().GetOatFileEnd();
          requested_alloc_space_begin = AlignUp(oat_file_end_addr, kPageSize);
        } 
      }
      bool separate_non_moving_space = is_zygote || support_homogeneous_space_compaction || IsMovingGc(foreground_collector_type_) || IsMovingGc(background_collector_type_);
      std::unique_ptr<MemMap> main_mem_map_1;
      std::unique_ptr<MemMap> main_mem_map_2;
      uint8_t* request_begin = requested_alloc_space_begin;
    
      if (separate_non_moving_space) {
        const char* space_name = is_zygote ? kZygoteSpaceName: kNonMovingSpaceName;
        //zygote space的map,起始地址紧挨着boot.oat,大小为64M
        non_moving_space_mem_map.reset(MemMap::MapAnonymous(space_name, requested_alloc_space_begin, non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false, &error_str));
        request_begin = reinterpret_cast<uint8_t*>(300 * MB);
      }
    
      if (foreground_collector_type_ != kCollectorTypeCC) {
        if (separate_non_moving_space) {
          // main space 1的map
          main_mem_map_1.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[0], request_begin, capacity_/*512M*/, &error_str));
        }
      }
    
      if (support_homogeneous_space_compaction ||  background_collector_type_ == kCollectorTypeSS ||foreground_collector_type_ == kCollectorTypeSS) {
        //main space 2的map
        main_mem_map_2.reset(MapAnonymousPreferredAddress(kMemMapSpaceName[1], main_mem_map_1->End(), capacity_, &error_str));
      }
    
      if (separate_non_moving_space) {
        const size_t size = non_moving_space_mem_map->Size();
        // 构建zygote space
        non_moving_space_ = space::DlMallocSpace::CreateFromMemMap(non_moving_space_mem_map.release(), "zygote / non moving space", kDefaultStartingSize, initial_size, size, size, false);
        non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
        AddSpace(non_moving_space_);
      }
    
      if (foreground_collector_type_ == kCollectorTypeCC) {
          ...
      } else if (IsMovingGc(foreground_collector_type_) && foreground_collector_type_ != kCollectorTypeGSS) {
      } else {
        //构建main space 1
        CreateMainMallocSpace(main_mem_map_1.release(), initial_size/*2M*/, growth_limit_/*256M*/, capacity_/*512M*/);
        AddSpace(main_space_);
        if (foreground_collector_type_ == kCollectorTypeGSS) {
          ...
        } else if (main_mem_map_2.get() != nullptr) {
          const char* name = kUseRosAlloc ? kRosAllocSpaceName[1] : kDlMallocSpaceName[1];
          //构建main space 2
          main_space_backup_.reset(CreateMallocSpaceFromMemMap(main_mem_map_2.release(), initial_size,  growth_limit_, capacity_, name, true));
          AddSpace(main_space_backup_.get());
        }
      }
      //构建large object space
      if (large_object_space_type == space::LargeObjectSpaceType::kFreeList) {
        large_object_space_ = space::FreeListSpace::Create("free list large object space", nullptr, capacity_);
      }
      ...
      if (large_object_space_ != nullptr) {
        AddSpace(large_object_space_);
      }
    }

    【image space】

    根据boot.art这个内存镜像文件创建的space,映射地址是boot.art里指定的。

    这块有系统的java类,其内存不会被释放,所以也不需要有堆管理模块。加载image space的同时会加载boot.oat文件。

    【main space】

    从300M的地址也就是0x12c00000开始的大小为512M的内存区域,绝大部分的object都利用这段空间。它的堆管理模块是RocAlloc。

    有一个相同大小的备用main space区域,暂时不清楚其用途。

    【zygote(non moving) space】

    紧挨着boot.oat的内存区域,大小为64M,zygote启动时是以non moving space的形式存在,

    主要用于non moving的object:主要是non moving的class或者从其他non moving区域里拷贝出来的对象,比如image space就是non moving区域。

    它的堆栈管理块是Dlmalloc。

    【large object space】

    紧挨着non moving spage的区域,申请大于等于12k的基本类型或者string类型的数组时会用到这部分内存,

    根据配置可分为FreeListSpace和LargeObjectMapSpace。

    其中LargeObjectMapSpace是次alloc和free都会调用系统的mmap和munmap,管理模块逻辑简单,但效率低。

    FreeListSpace会一次性mmap一块512M内存,用一个相对复杂点的(相对于RocAlloc和Dlmalloc简单的多)逻辑管理这块内存,效率高比LargeObjectMapSpace高。

    一般系统默认用FreeListSpace作为large object space。

    在虚拟机初始化完成前,也就是fork第一个进程(system server)前,调用art::gc::Heap::PreZygoteFork()函数进行一次调整,其调用栈为:

    main()@frameworks/base/cmds/app_process/app_main.cpp
        com.android.internal.os.ZygoteInit.main()@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
            com.android.internal.os.ZygoteInit.startSystemServer@frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
                com.android.internal.os.Zygote.forkSystemServer()@frameworks/base/core/java/com/android/internal/os/Zygote.java
                    dalvik.system.ZygoteHooks.preFork()@libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
                        dalvik.system.ZygoteHooks.nativePreFork()@libcore/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
                            art::ZygoteHooks_nativePreFork()@art/runtime/native/dalvik_system_ZygoteHooks.cc
                                art::Runtime::PreZygoteFork()@art/runtime/runtime.cc
                                    art::gc::Heap::PreZygoteFork()@art/runtime/gc/heap.cc

    调整的目的是将虚拟机初始化阶段生成的main space和non moving space里的对象,合并成一块儿内存,

    这部分内存之在虚拟机初始化完成后不会被改变,将他们统一成一个区域,可以共享给所有zygote fork出来的进程,既节省内存,也方便gc管理。

    void Heap::PreZygoteFork() {
      ...
      if (kCompactZygote) {
        ...
        ZygoteCompactingCollector zygote_collector(this);
        //找到non_moving_space_中的空闲区域,用于插入man_space_里的对象
        zygote_collector.BuildBins(non_moving_space_);
        ...
        bool reset_main_space = false;
        if (IsMovingGc(collector_type_)) {
          ...
        } else {
          zygote_collector.SetFromSpace(main_space_);
          reset_main_space = true;
        }
        zygote_collector.SetToSpace(&target_space);
        zygote_collector.SetSwapSemiSpaces(false);
        //将main_space_中的对象插入到non_moving_space_中
        zygote_collector.Run(kGcCauseCollectorTransition, false);
        if (reset_main_space) {
          //重新构建main space
          main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
          madvise(main_space_->Begin(), main_space_->Capacity(), MADV_DONTNEED);
          MemMap* mem_map = main_space_->ReleaseMemMap();
          RemoveSpace(main_space_);
          space::Space* old_main_space = main_space_;
          CreateMainMallocSpace(mem_map, kDefaultInitialSize, std::min(mem_map->Size(), growth_limit_), mem_map->Size());
          delete old_main_space;
          AddSpace(main_space_);
        } else {
          ...
        }
        ...
        non_moving_space_->SetEnd(target_space.End());
        non_moving_space_->SetLimit(target_space.Limit());
      }
      ChangeCollector(foreground_collector_type_);
      space::MallocSpace* old_alloc_space = non_moving_space_;
      RemoveSpace(old_alloc_space);
      //原先的non moving space被拆分为zygote space和新non moving space
      zygote_space_ = old_alloc_space->CreateZygoteSpace(kNonMovingSpaceName, low_memory_mode_, &non_moving_space_);
      delete old_alloc_space;
      AddSpace(zygote_space_);
      non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
      AddSpace(non_moving_space_);
      ...
    }

    合并前main_space_的管理模块是RosAlloc,而non_moving_space_的管理模块是Dlmalloc。

    由于合并后的内存是不会被释放的,也就不需要管理模块,所以这种合并是可行的。

    space的继承关系如下:

  • 相关阅读:
    e621. Activating a Keystroke When Any Child Component Has Focus
    e587. Filling Basic Shapes
    e591. Drawing Simple Text
    e595. Drawing an Image
    e586. Drawing Simple Shapes
    e636. Listening to All Key Events Before Delivery to Focused Component
    在 PL/SQL 块的哪部分可以对初始变量赋予新值? (选择1项)
    Oracle数据库中,在SQL语句中连接字符串的方法是哪个?(选择1项)
    你判断下面语句,有什么作用?(单选)
    Oracle数据库表空间与数据文件的关系描述正确的是( )
  • 原文地址:https://www.cnblogs.com/YYPapa/p/6851299.html
Copyright © 2011-2022 走看看