Android U ART young cc流程分析

 概述:

  众所周知jvm虚拟机为了提高内存回收效率,更高效的进行内存管理与回收,对堆内存进行了分代管理比如hotspot虚拟机的新生代,老年代。根据各代的特征( 新生代对象分配频繁而生存周期短,老年代生存周期长不需要频繁回收)来应用不同的内存回收算法

  art虚拟机也是如此,不过Android U上年轻代、老年代回收都采用的concurrent_copying回收算法,虚拟机定义了gc_type枚举类来定义不同的回收策略

enum GcType {
  kGcTypeNone,
  //粘性回收,只回收上次回收后分配的对象
  kGcTypeSticky,
  //部分回收,回收初zygote space之外的应用堆内存
  kGcTypePartial,
  //圈梁回收,应用堆包括zygote space
  kGcTypeFull,
  kGcTypeMax,
};

  枚举类型自上至下回收力度逐渐增大,本文主要分析kGcTypeSticky,其他回收类型后续文章再分析

 

 上图可以是在进行并发回收任务的时候(HeapTaskDaemon线程),如果没有找到合适的回收类型,会依次进行力度更大的回收

如果回收类型为 kGcTypeSticky,会启动年轻代回收器进行回收,那年轻代回收器到底是什么,都回收哪块内存就是我们今天要阐述的内容。

 并发拷贝cc算法的一般流程:初始化->标记->复制->回收

 art虚拟中并发拷贝算法的实现类concurrent_copying 中的gc全貌

void ConcurrentCopying::RunPhases() {
  CHECK(kUseBakerReadBarrier || kUseTableLookupReadBarrier);
  CHECK(!is_active_);
  is_active_ = true;
  Thread* self = Thread::Current();
  thread_running_gc_ = self;
  Locks::mutator_lock_->AssertNotHeld(self);
  {
    ReaderMutexLock mu(self, *Locks::mutator_lock_);
    InitializePhase(); //初始化阶段
    // In case of forced evacuation, all regions are evacuated and hence no
    // need to compute live_bytes.
    if (use_generational_cc_ && !young_gen_ && !force_evacuate_all_) {
      MarkingPhase(); 
    }
  }
  if (kUseBakerReadBarrier && kGrayDirtyImmuneObjects) {
    // Switch to read barrier mark entrypoints before we gray the objects. This is required in case
    // a mutator sees a gray bit and dispatches on the entrypoint. (b/37876887).
    ActivateReadBarrierEntrypoints();
    // Gray dirty immune objects concurrently to reduce GC pause times. We re-process gray cards in
    // the pause.
    ReaderMutexLock mu(self, *Locks::mutator_lock_);
    GrayAllDirtyImmuneObjects();
  }
  FlipThreadRoots(); //threadroots切换阶段
  {
    ReaderMutexLock mu(self, *Locks::mutator_lock_);
    CopyingPhase(); //复制阶段
  }
  // Verify no from space refs. This causes a pause.
  if (kEnableNoFromSpaceRefsVerification) {
    TimingLogger::ScopedTiming split("(Paused)VerifyNoFromSpaceReferences", GetTimings());
    ScopedPause pause(this, false);
    CheckEmptyMarkStack();
    if (kVerboseMode) {
      LOG(INFO) << "Verifying no from-space refs";
    }
    VerifyNoFromSpaceReferences();
    if (kVerboseMode) {
      LOG(INFO) << "Done verifying no from-space refs";
    }
    CheckEmptyMarkStack();
  }
  {
    ReaderMutexLock mu(self, *Locks::mutator_lock_);
    ReclaimPhase();//回收阶段
  }
  FinishPhase();
  CHECK(is_active_);
  is_active_ = false;
  thread_running_gc_ = nullptr;
}

1. 初始化阶段


void ConcurrentCopying::InitializePhase() {
  TimingLogger::ScopedTiming split("InitializePhase", GetTimings());
  num_bytes_allocated_before_gc_ = static_cast<int64_t>(heap_->GetBytesAllocated());
 
  CheckEmptyMarkStack();
 

  BindBitmaps();

  if (use_generational_cc_ && !young_gen_) {
    region_space_bitmap_->Clear(ShouldEagerlyReleaseMemoryToOS());
  }
  mark_stack_mode_.store(ConcurrentCopying::kMarkStackModeThreadLocal, std::memory_order_release);
  MarkZygoteLargeObjects();
}


void ConcurrentCopying::BindBitmaps() {
  Thread* self = Thread::Current();
  WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
  // Mark all of the spaces we never collect as immune.
  for (const auto& space : heap_->GetContinuousSpaces()) {
    if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect ||
        space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect) {
      CHECK(space->IsZygoteSpace() || space->IsImageSpace());
      immune_spaces_.AddSpace(space); //imagespace zygote space添加到不动space
    } else {
      CHECK(!space->IsZygoteSpace());
      CHECK(!space->IsImageSpace());
      CHECK(space == region_space_ || space == heap_->non_moving_space_);
      if (use_generational_cc_) {
        if (space == region_space_) {
          region_space_bitmap_ = region_space_->GetMarkBitmap();
        } else if (young_gen_ && space->IsContinuousMemMapAllocSpace()) {
          DCHECK_EQ(space->GetGcRetentionPolicy(), space::kGcRetentionPolicyAlwaysCollect);
          space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
        }
        if (young_gen_) {
          // Age all of the cards for the region space so that we know which evac regions to scan.
          heap_->GetCardTable()->ModifyCardsAtomic(space->Begin(),
                                                   space->End(),
                                                   AgeCardVisitor(),
                                                   VoidFunctor());
        } else {
          heap_->GetCardTable()->ClearCardRange(space->Begin(), space->Limit());
        }
      } 
    }
  }
  if (use_generational_cc_ && young_gen_) {
    for (const auto& space : GetHeap()->GetDiscontinuousSpaces()) {
      CHECK(space->IsLargeObjectSpace());
      space->AsLargeObjectSpace()->CopyLiveToMarked();
    }
  }
}

2.标记阶段

void ConcurrentCopying::FlipThreadRoots() {
  TimingLogger::ScopedTiming split("FlipThreadRoots", GetTimings());
  if (kVerboseMode || heap_->dump_region_info_before_gc_) {
    LOG(INFO) << "time=" << region_space_->Time();
    region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
  }
  Thread* self = Thread::Current();
  Locks::mutator_lock_->AssertNotHeld(self);
  ThreadFlipVisitor thread_flip_visitor(this, heap_->use_tlab_);
  FlipCallback flip_callback(this);

  Runtime::Current()->GetThreadList()->FlipThreadRoots(
      &thread_flip_visitor, &flip_callback, this, GetHeap()->GetGcPauseListener());

  is_asserting_to_space_invariant_ = true;
  QuasiAtomic::ThreadFenceForConstructor();  // TODO: Remove?
  if (kVerboseMode) {
    LOG(INFO) << "time=" << region_space_->Time();
    region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
    LOG(INFO) << "GC end of FlipThreadRoots";
  }
}

hotspot虚拟机中8:1比例划分对新生代堆空间进行划分,大空间分配的对象往往朝生夕死,当内存被回收后会被拷贝到小空间,art虚拟机虽然也采用分代策略但是采用了不同的机制

art虚拟机中应用分配的普通对象会分配在main_space(region_space类实现)空间,而>12k的string类型或者原始数组类型会分配到large_object_space空间

  enum class RegionType : uint8_t {
    kRegionTypeAll,              // All types.
    kRegionTypeFromSpace,        // From-space. To be evacuated.
    kRegionTypeUnevacFromSpace,  // Unevacuated from-space. Not to be evacuated.
    kRegionTypeToSpace,          // To-space.
    kRegionTypeNone,             // None.
  };

FlipThreadRoot 会进行

a. region_space类型切换

regionspace由一个个固定大小的region组成,分配对象的region类型为kRegionTypeToSpace,而当需要内存回收的时候会切换为kRegionTypeFromSpace(拷贝从from拷贝的to)代码位置在FlipCallback->setFromSpace

b. 标记gcroot

 art虚拟机中的gcroot-CSDN博客可以参考这篇文章,被标记的对象会被压入到mark_stack(PushOntoMarkStack)中

那kGcTypeSticky回收策略是怎么做到只回收上次分配的对象的呢?

inline bool RegionSpace::Region::ShouldBeEvacuated(EvacMode evac_mode) {

  if (IsLarge()) {
    return false;
  }
  if (UNLIKELY(evac_mode == kEvacModeForceAll)) {
    return true;
  }
  DCHECK(IsAllocated());
  if (is_newly_allocated_) {

    return true;
  } else if (evac_mode == kEvacModeLivePercentNewlyAllocated) {
    bool is_live_percent_valid = (live_bytes_ != static_cast<size_t>(-1));
    if (is_live_percent_valid) {
    
      return live_bytes_ * 100U < kEvacuateLivePercentThreshold * bytes_allocated;
    }
  }
  return false;
}

当空间是新分配或者存活对象比例低于75%,才会设置成kRegionTypeFromSpace,即需要被复制的空间

3.复制阶段

CopyingPhase(); //复制阶段, 

for (auto& space : immune_spaces_.GetSpaces()) {
      DCHECK(space->IsImageSpace() || space->IsZygoteSpace());
      accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
      accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
      ImmuneSpaceScanObjVisitor visitor(this);
      if (kUseBakerReadBarrier && kGrayDirtyImmuneObjects && table != nullptr) {
        table->VisitObjects(ImmuneSpaceScanObjVisitor::Callback, &visitor);
      } else {
        WriterMutexLock rmu(Thread::Current(), *Locks::heap_bitmap_lock_);
        card_table->Scan<false>(
            live_bitmap,
            space->Begin(),
            space->Limit(),
            visitor,
            accounting::CardTable::kCardDirty - 1);
      }
}

需要把immuse space(zygote space,imagespace)中的存活对象进行拷贝,ImageSpace中的对象可以直接标记,因为映射dex 等Image文件所以可以直接被认为是gcroot

广度优先遍历mark_stack,把mark_stack中的对象及其引用拷贝到toSpace中,同时

4.回收阶段

回收fromspace(非stick会回收largetObjecSpace)

5.结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/924462.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ 11重点总结1

智能指针 智能指针: C11引入了四种智能指针: auto_ptr(已弃用)、unique_ptr、shared_ptr和weak_ptr。智能指针可以更有效地管理堆内存,并避免常见的内存泄漏问题。 shared_ptr: 自定义删除器。 shared_ptr使用引用计数来管理它指向的对象的生命周期。多个shared_ptr实例可以指向…

Sickos1.1 详细靶机思路 实操笔记

Sickos1.1 详细靶机思路 实操笔记 免责声明 本博客提供的所有信息仅供学习和研究目的&#xff0c;旨在提高读者的网络安全意识和技术能力。请在合法合规的前提下使用本文中提供的任何技术、方法或工具。如果您选择使用本博客中的任何信息进行非法活动&#xff0c;您将独自承担…

GB28181系列二:SIP信令

我的音视频/流媒体开源项目(github) GB28181系列目录 目录 一、SIP报文介绍 二、SIP交互流程&#xff1a; 1、Session Model 2、Pager Model 3、SIP信令交互过程中的3个定义 三、媒体传输&#xff08;SDP和RTP&#xff09; 一、SIP报文介绍 这里将会介绍SIP…

【接口自动化测试】一文从0到1详解接口测试协议!

接口自动化测试是软件开发过程中重要的环节之一。通过对接口进行测试&#xff0c;可以验证接口的功能和性能&#xff0c;确保系统正常运行。本文将从零开始详细介绍接口测试的协议和规范。 定义接口测试协议 接口测试协议是指用于描述接口测试的规范和约定。它包含了接口的请求…

CentOS7执行yum命令报错,已加载插件:fastestmirrorLoading mirror speeds from cached hostfile

一、出现一下异常问题&#xff0c;表示域名没有配置或配置错误 问题一&#xff1a; 0curl: (6) Could not resolve host: mirrors.aliyun.com; 未知的错误 问题二&#xff1a;虚拟机使用ping主机&#xff0c;提示network unreachable 2.原因分析 出现这个问题是因为yum在安装…

【Threejs进阶教程-着色器篇】9.顶点着色器入门

【Threejs进阶教程-着色器篇】9.顶点着色器入门 本系列教程第一篇地址&#xff0c;建议按顺序学习认识顶点着色器varying介绍顶点着色器与片元着色器分别的作用Threejs在Shader中的内置变量各种矩阵gl_Position 尝试使用顶点着色器增加分段数增强效果 制作平面鼓包效果鼓包效果…

Ubuntu 硬盘分区并挂载

一、什么是挂载 1.挂载的定义 在 Ubuntu&#xff08;或其他 Linux 系统&#xff09;中&#xff0c;挂载&#xff08;Mount&#xff09; 是将一个存储设备或分区连接到系统的文件系统层次结构中的过程。挂载后&#xff0c;你可以通过某个目录&#xff08;挂载点&#xff09;访问…

【前端开发】一文带你快速入门 JavaScript(上)Web 前端必备程序语言 | 环境搭建与基础知识

&#x1f4af; 欢迎光临清流君的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落 &#x1f4af; &#x1f525; 个人主页:【清流君】&#x1f525; &#x1f4da; 系列专栏: 运动控制 | 决策规划 | 机器人数值优化 &#x1f4da; &#x1f31f;始终保持好奇心&…

视频推拉流EasyDSS互联网直播点播平台技术特点及应用场景剖析

在数字科技日新月异的今天&#xff0c;视频直播和点播已经成为互联网内容传播的重要方式之一。而互联网直播点播平台EasyDSS作为功能强大的流媒体直播点播视频能力平台&#xff0c;提供了一站式的视频推拉流、转码、直播、点播、时移回放、存储等视频服务&#xff0c;广泛应用于…

Qt读写Usb设备的数据

Qt读写Usb设备的数据 问题:要读取usb设备进行通讯&#xff0c;qt好像没有对应的库支持。解决&#xff1a;libusbwindow下载 :Linux下载: QtUsb 开源的第三方库库里面的函数说明&#xff1a;window版本&#xff1a;Linux中也提供的直接下载测试代码&#xff1a;库下载&#xff1…

2024最新python使用yt-dlp

2024最新python使用yt-dlp下载YT视频 1.获取yt的cookie1&#xff09;google浏览器下载Get cookies.txt LOCALLY插件2&#xff09;导出cookie 2.yt-dlp下载[yt-dlp的GitHub地址](https://github.com/yt-dlp/yt-dlp?tabreadme-ov-file)1&#xff09;使用Pycharm(2024.3)进行代码…

一加ACE 3 Pro手机无法连接电脑传输文件问题

先说结论&#xff1a;OnePlus手机无法连接电脑传输数据的原因&#xff0c;大概率是一加数据线的问题。尝试其他手机品牌的数据线&#xff08;比如华为&#xff09;&#xff0c;再次尝试。 连接电脑方法&#xff1a; 1 打开开发者模式&#xff08;非必要操作&#xff09; 进入…

java:aqs实现自定义锁

aqs采用模板方式设计模式&#xff0c;需要重写方法 package com.company.aqs;import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock;…

linux系统下如何将xz及ISO\img等格式压缩包(系统)烧写到优盘(TF卡)

最近用树莓派做了个NAS&#xff0c;效果一般&#xff0c;缺少监控及UI等&#xff0c;详细见这篇文章&#xff1a; https://blog.csdn.net/bugsycrack/article/details/135344782?spm1001.2014.3001.5501 所以下载了专门的基于树莓派的NAS系统直接使用。这篇文章是顺便复习一…

python除了熟悉的pandas,openpyxl库也很方便的支持编辑Excel表

excel表格是大家经常用到的文件格式&#xff0c;各行各业都会跟它打交道。之前文章我们介绍了使用openpyxl和xlrd库读取excel表数据&#xff0c;使用xlwt库创建和编辑excel表&#xff0c;在办公自动化方面可以方便我们快速处理数据&#xff0c;帮助我们提升效率。 python之open…

【VUE3】新版Vue3+ElementPlus全家桶开发视频项目实战

VUE 介绍 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 Vue.js是一个MVVM(Model - View - ViewModel)的SPA框架。 Model:数…

介绍一下atol(arr);(c基础)

hi , I am 36 适合对象c语言初学者 atol(arr)&#xff1b;是返回整数(long型)&#xff0c;整数是arr数组中字符中数字 格式 #include<stdio.h> atol(arr); 返回值arr数组中的数字 未改变arr数组 #include<stdio.h> //atol(arr); 返 <stdlib> int main…

微信小程序WXSS全局样式与局部样式的使用教程

微信小程序WXSS全局样式与局部样式的使用教程 引言 在微信小程序的开发中,样式的设计与实现是提升用户体验的关键部分。WXSS(WeiXin Style Sheets)作为微信小程序的样式表语言,不仅支持丰富的样式功能,还能通过全局样式与局部样式的灵活运用,帮助开发者构建美观且易于维…

OceanBase 大数据量导入(obloader)

现需要将源数据库&#xff08;Oracle|MySQL等&#xff09;一些表的海量数据迁移到目标数据库 OceanBase 中&#xff0c;基于常规 jdbc 驱动编码的方式涉及开发工作&#xff0c;性能效率也要看编码的处理机制。 OceanBase 官方提供了的 OceanBase Migration Service (OMS) 数据…

Spring Boot框架:英语知识网站构建指南

3系统分析 3.1可行性分析 通过对本英语知识应用网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本英语知识应用网站采用SSM框架&#xff0c;JAVA作为开发语…