热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ART的堆内存布局

ART堆内存由若干个space组成,map表中的space的布局如下:非等比例图如下:如上图,可分为如下几种space:mainspace、imagespace、zygotespa

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 main_mem_map_1;
  std::unique_ptr 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(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的继承关系如下:技术分享

ART的堆内存布局


推荐阅读
  • DSP中cmd文件的命令文件组成及其作用
    本文介绍了DSP中cmd文件的命令文件的组成和作用,包括链接器配置文件的存放链接器配置信息、命令文件的组成、MEMORY和SECTIONS两个伪指令的使用、CMD分配ROM和RAM空间的目的以及MEMORY指定芯片的ROM和RAM大小和划分区间的方法。同时强调了根据不同芯片进行修改的必要性,以适应不同芯片的存储用户程序的需求。 ... [详细]
  • 本文主要复习了数据库的一些知识点,包括环境变量设置、表之间的引用关系等。同时介绍了一些常用的数据库命令及其使用方法,如创建数据库、查看已存在的数据库、切换数据库、创建表等操作。通过本文的学习,可以加深对数据库的理解和应用能力。 ... [详细]
  • 在编写业务代码时,常常会遇到复杂的业务逻辑导致代码冗长混乱的情况。为了解决这个问题,可以利用中间件模式来简化代码逻辑。中间件模式可以帮助我们更好地设计架构和代码,提高代码质量。本文介绍了中间件模式的基本概念和用法。 ... [详细]
  • 本文介绍了在Ubuntu下制作deb安装包及离线安装包的方法,通过备份/var/cache/apt/archives文件夹中的安装包,并建立包列表及依赖信息文件,添加本地源,更新源列表,可以在没有网络的情况下更新系统。同时提供了命令示例和资源下载链接。 ... [详细]
  • 代理模式的详细介绍及应用场景
    代理模式是一种在软件开发中常用的设计模式,通过在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象进行访问,从而简化系统的复杂性。代理模式可以根据不同的使用目的分为远程代理、虚拟代理、Copy-on-Write代理、保护代理、防火墙代理、智能引用代理和Cache代理等几种。本文将详细介绍代理模式的原理和应用场景。 ... [详细]
  • 本文介绍了在Windows系统下安装Python、setuptools、pip和virtualenv的步骤,以及安装过程中需要注意的事项。详细介绍了Python2.7.4和Python3.3.2的安装路径,以及如何使用easy_install安装setuptools。同时提醒用户在安装完setuptools后,需要继续安装pip,并注意不要将Python的目录添加到系统的环境变量中。最后,还介绍了通过下载ez_setup.py来安装setuptools的方法。 ... [详细]
  • 本文详细介绍了在Centos7上部署安装zabbix5.0的步骤和注意事项,包括准备工作、获取所需的yum源、关闭防火墙和SELINUX等。提供了一步一步的操作指南,帮助读者顺利完成安装过程。 ... [详细]
  • Merge k sortedlinkedlistsandreturnitasonesortedlist.Analyzeanddescribeitscomplexity. ... [详细]
  • 在project.properties添加#Projecttarget.targetandroid-19android.library.reference.1..Sliding ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 本文介绍了一种解析GRE报文长度的方法,通过分析GRE报文头中的标志位来计算报文长度。具体实现步骤包括获取GRE报文头指针、提取标志位、计算报文长度等。该方法可以帮助用户准确地获取GRE报文的长度信息。 ... [详细]
  • PDF内容编辑的两种小方法,你知道怎么操作吗?
    本文介绍了两种PDF内容编辑的方法:迅捷PDF编辑器和Adobe Acrobat DC。使用迅捷PDF编辑器,用户可以通过选择需要更改的文字内容并设置字体形式、大小和颜色来编辑PDF文件。而使用Adobe Acrobat DC,则可以通过在软件中点击编辑来编辑PDF文件。PDF文件的编辑可以帮助办公人员进行文件内容的修改和定制。 ... [详细]
  • CentOS 6.5安装VMware Tools及共享文件夹显示问题解决方法
    本文介绍了在CentOS 6.5上安装VMware Tools及解决共享文件夹显示问题的方法。包括清空CD/DVD使用的ISO镜像文件、创建挂载目录、改变光驱设备的读写权限等步骤。最后给出了拷贝解压VMware Tools的操作。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
author-avatar
木瓜香皂a
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有