前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入了解Android垃圾回收机制

深入了解Android垃圾回收机制

作者头像
陆业聪
发布2024-07-23 18:26:25
520
发布2024-07-23 18:26:25
举报
文章被收录于专栏:大前端修炼手册

关于Android的垃圾回收机制,之前笔者也有发过相关的文章,但是这次增加了一部分GC源码的分析。本文的第一到第五部分,介绍GC算法的基本原理和常见优化方式。第六部分介绍Android中GC算法的部分源码实现。读者可以按需要阅读。

在Android应用开发中,内存管理和垃圾回收(GC)对于应用性能和稳定性至关重要。理解GC机制有助于我们编写更高效的代码,避免内存泄漏和内存溢出。本文将深入探讨Android GC机制的工作原理。如果对内存管理感兴趣,还可以阅读我的文章Android内存优化实战

一、内存分配

Android应用运行在Dalvik虚拟机(Android 4.4之前)或ART虚拟机(Android 4.4及之后)上。虚拟机负责为应用分配和管理内存。当应用需要分配内存时,虚拟机会在堆内存中分配一块空间。堆内存是应用所有线程共享的内存区域,用于存储对象和数据。

随着应用的运行,堆内存中会不断产生新的对象。当对象不再被使用时,它们占用的内存需要被回收,以便为新的对象分配空间。这就是垃圾回收的主要任务。

二、垃圾回收触发条件

垃圾回收可以由以下条件触发:

  • 堆内存不足:当应用试图分配内存,但堆内存不足以满足需求时,GC会被触发,以回收不再使用的对象占用的内存。
  • 显式调用:应用可以通过调用System.gc()来显式触发GC。然而,这种做法通常不推荐,因为它可能导致GC过于频繁,影响应用性能。
  • 定期执行:虚拟机可能会定期执行GC,以保持堆内存的整洁。这种情况下,GC的触发时机是由虚拟机决定的。

三、GC算法

Android操作系统使用的是Dalvik虚拟机或者ART(Android RunTime)来执行应用程序的代码。这两种虚拟机在垃圾回收(GC)算法上有所不同。

3.1 Dalvik虚拟机的GC算法

Dalvik虚拟机主要使用标记-清除(Mark-Sweep)和标记-压缩(Mark-Compact)两种GC算法。

  • 标记-清除算法:
    1. 在标记阶段,从GC Roots(垃圾回收的根节点,如全局变量、栈中的局部变量等)开始,遍历所有的引用关系,把所有能访问到的对象标记为存活。这个过程可以通过深度优先搜索(DFS)或者广度优先搜索(BFS)完成。
    2. 在清除阶段,垃圾回收器会清除掉所有未被标记(即不可达)的对象,回收它们占用的内存。
    3. 这种算法的主要问题是会产生内存碎片,以及在标记和清除阶段需要暂停应用程序的运行(Stop-The-World)。
  • 标记-压缩算法:为了解决内存碎片的问题,Dalvik虚拟机在内存紧张时会使用标记-压缩算法。这种算法在标记-清除的基础上,增加了一个压缩阶段,将所有存活的对象移到内存的一端,从而减少内存碎片。

3.2 ART的GC算法

ART在Dalvik的基础上做了很多优化,包括在垃圾回收算法上。ART主要使用分代收集(Generational Collection)和并发标记-清除(Concurrent Mark-Sweep,CMS)两种GC算法。

  • 分代收集:这种算法将内存分为几个区域(代),根据对象的生命周期将其放入不同的代中。通常,新创建的对象会被放入新生代,经过多次GC仍然存活的对象会被放入老年代。分代收集可以减少GC的开销,因为大部分对象都是短暂存在的,只需要对新生代进行GC即可。分代回收算法的主要优点是它可以减少全局GC的次数,从而提高应用性能。Android虚拟机将堆内存划分为以下几个代:
    • 年轻代(Young Generation):新创建的对象分配在年轻代。年轻代的GC频率较高,但回收速度较快,因为大多数新创建的对象生命周期较短。
    • 老年代(Old Generation):从年轻代晋升的对象分配在老年代。老年代的GC频率较低,但回收速度较慢,因为老年代中的对象生命周期较长。
    • 永久代(Permanent Generation):用于存储类元数据和静态变量。永久代的GC频率最低,但回收速度最慢。Android虚拟机使用以下算法执行垃圾回收:
  • 并发标记-清除:这种算法在标记和清除阶段会并发(同时)执行,从而减少了应用程序的暂停时间。这对于用户体验来说是一个重要的改进,因为用户不会因为GC而感觉到应用程序的卡顿。

总的来说,Android虚拟机的GC算法是为了在保证内存使用效率的同时,尽可能减少GC对应用程序性能和用户体验的影响。

四、优化GC性能

为了减少垃圾回收对应用性能的影响,我们可以采取以下措施:

  • 减少对象创建:避免不必要的对象创建,尽量重用已有对象。例如,可以使用对象池来重用对象,或者使用静态工厂方法来创建对象。
  • 使用弱引用和软引用:对于不需要长时间持有的对象,可以使用弱引用(WeakReference)或软引用(SoftReference)来代替强引用。这样,垃圾回收器可以在需要时回收这些对象,从而减少内存占用。
  • 避免内存泄漏:内存泄漏是指应用程序无法释放不再使用的对象占用的内存。内存泄漏会导致堆内存不断增长,从而引发频繁的垃圾回收。为了避免内存泄漏,我们需要确保正确关闭资源(如文件、数据库连接等),并在不再需要时解除对象引用。
  • 避免使用全局静态变量:全局静态变量会导致对象的生命周期延长,从而增加GC的负担。尽量使用局部变量和传递参数的方式来共享对象。
  • 优化数据结构:使用合适的数据结构和算法可以减少内存占用和对象创建。例如,可以使用SparseArray代替HashMap来存储稀疏的键值对。

五、监控GC耗时情况

监控GC(Garbage Collection)耗时情况是一个重要的性能优化手段。GC过程会暂停应用的运行,因此,频繁的GC会影响应用的启动速度和响应速度。以下是一些常用的监控方法:

  1. 使用Android Studio的Profiler工具:Android Studio自带的Profiler工具可以帮助我们监控应用的运行情况,包括GC的耗时情况。我们可以在Profiler工具的Memory选项卡中看到GC的详细信息,包括GC的次数,每次GC的耗时,以及每次GC后的内存使用情况。
  2. 使用adb命令:我们可以使用adb命令来获取应用的GC信息。例如,我们可以使用adb shell dumpsys meminfo <package_name>命令来获取应用的内存使用情况,其中包括GC的次数和总耗时。我们还可以使用adb logcat -s GC命令来获取GC的详细日志。
  3. 使用代码:我们可以在代码中使用Debug.startMethodTracing()Debug.stopMethodTracing()方法来开启和关闭方法追踪,然后使用Debug.getNativeHeapAllocatedSize()方法来获取已分配的内存大小。通过比较两次调用Debug.getNativeHeapAllocatedSize()方法的结果,我们可以估计GC的耗时。

以上方法可以帮助我们监控Android中的GC耗时情况。通过监控,我们可以找出频繁GC的原因,如内存泄漏,过度分配等,并进行相应的优化,从而提高应用的启动速度和响应速度。

六、Android运行时的垃圾回收器:HeapTask

6.1 HeapTask简介

HeapTask是Android中用于处理内存相关任务的基础类,它位于art/runtime/gc/task_processor.h。HeapTask的主要作用是对内存进行垃圾回收、内存整理以及内存压缩等操作,以便在应用程序运行时释放不再使用的内存。HeapTask的实现基于Android运行时的垃圾回收器(Garbage Collector,GC)。

HeapTask的主要原理是通过标记-清除(Mark-Sweep)算法来识别和回收不再使用的内存。在标记阶段,垃圾回收器会从根对象开始,遍历所有可达对象,并将它们标记为存活。在清除阶段,垃圾回收器会回收所有未标记的对象所占用的内存。

在Android源码中,HeapTask类的定义如下:

代码语言:javascript
复制
// HeapTask类,继承自SelfDeletingTask
class HeapTask : public SelfDeletingTask {
 public:
  // 构造函数,需要传入一个目标运行时间(纳秒)
  explicit HeapTask(uint64_t target_run_time) : target_run_time_(target_run_time) {
  }
  
  // 获取目标运行时间的方法
  uint64_t GetTargetRunTime() const {
    return target_run_time_;
  }

 private:
  // 更新目标运行时间,任务处理器会在任务弹出时重新插入任务,并更新目标运行时间
  void SetTargetRunTime(uint64_t new_target_run_time) {
    target_run_time_ = new_target_run_time;
  }

  // 目标运行时间(纳秒)
  uint64_t target_run_time_;

  // 声明TaskProcessor为友元类,以便访问私有成员
  friend class TaskProcessor;
  
  // 禁止使用隐式构造函数
  DISALLOW_IMPLICIT_CONSTRUCTORS(HeapTask);
};

HeapTask 类是一个继承自 SelfDeletingTask 的任务类,用于表示堆任务。它包含一个目标运行时间(target_run_time_),以纳秒为单位。在构造函数中,需要传入目标运行时间。类中还提供了获取和设置目标运行时间的方法。此外,TaskProcessor 类被声明为友元类,以便访问 HeapTask 的私有成员。最后,禁止使用隐式构造函数。

6.2 HeapTask的子类类型

以下是结合源码对 Android 中每个 HeapTask 的作用的详细解释:

6.2.1 ConcurrentGCTask

当 Java 内存达到阈值时,会执行此任务。它用于执行并发垃圾回收(GC),以在后台线程中清理不再使用的内存。这种机制可以在不阻塞应用程序主线程的情况下,有效地回收内存。

代码语言:javascript
复制
// Heap::ConcurrentGCTask类,继承自HeapTask,表示并发垃圾回收任务
class Heap::ConcurrentGCTask : public HeapTask {
 public:
  // 构造函数,接收目标运行时间、GC原因、是否强制执行全量回收以及GC序列号
  ConcurrentGCTask(uint64_t target_time, GcCause cause, bool force_full, uint32_t gc_num)
      : HeapTask(target_time), cause_(cause), force_full_(force_full), my_gc_num_(gc_num) {}
      
  // 重写Run方法,执行并发GC任务
  void Run(Thread* self) override {
    // 获取当前运行时和堆
    Runtime* runtime = Runtime::Current();
    gc::Heap* heap = runtime->GetHeap();
    // 检查GC序列号是否小于当前GC序列号 + 2
    DCHECK(GCNumberLt(my_gc_num_, heap->GetCurrentGcNum() + 2));  // <= current_gc_num + 1
    // 执行并发GC
    heap->ConcurrentGC(self, cause_, force_full_, my_gc_num_);
    // 检查当前GC序列号是否小于my_gc_num_,如果是,则运行时应该处于关闭状态
    CHECK_IMPLIES(GCNumberLt(heap->GetCurrentGcNum(), my_gc_num_), runtime->IsShuttingDown(self));
  }

 private:
  const GcCause cause_;           // GC原因
  const bool force_full_;         // 如果为true,则强制执行全量(或部分)回收
  const uint32_t my_gc_num_;      // 请求的GC序列号
};

Heap::ConcurrentGCTask 类是一个继承自 HeapTask 的任务类,用于表示并发垃圾回收任务。在构造函数中,需要传入目标运行时间、GC 原因、是否强制执行全量回收以及 GC 序列号。

Run 方法是执行并发 GC 任务的核心逻辑。首先,获取当前运行时和堆,然后检查 GC 序列号是否小于当前 GC 序列号 + 2。接着,调用 heap->ConcurrentGC() 方法执行并发 GC。最后,检查当前 GC 序列号是否小于 my_gc_num_,如果是,则运行时应该处于关闭状态。

6.2.2 CollectorTransitionTask

当应用程序从前台切换到后台时,会执行此任务。它用于切换 GC 类型,例如在后台时,可能会切换到拷贝回收这种 GC 机制。这有助于在不影响用户体验的情况下,更高效地回收内存。

代码语言:javascript
复制
// Heap::CollectorTransitionTask类,继承自HeapTask,表示收集器切换任务
class Heap::CollectorTransitionTask : public HeapTask {
 public:
  // 构造函数,接收目标运行时间
  explicit CollectorTransitionTask(uint64_t target_time) : HeapTask(target_time) {}

  // 重写Run方法,执行收集器切换任务
  void Run(Thread* self) override {
    // 获取当前运行时的堆
    gc::Heap* heap = Runtime::Current()->GetHeap();
    // 执行待处理的收集器切换
    heap->DoPendingCollectorTransition();
    // 清除待处理的收集器切换
    heap->ClearPendingCollectorTransition(self);
  }
};

Heap::CollectorTransitionTask 类是一个继承自 HeapTask 的任务类,用于表示收集器切换任务。在构造函数中,需要传入目标运行时间。

Run 方法是执行收集器切换任务的核心逻辑。首先,获取当前运行时的堆。接着,调用 heap->DoPendingCollectorTransition() 方法执行待处理的收集器切换。最后,调用 heap->ClearPendingCollectorTransition(self) 方法清除待处理的收集器切换。这个任务主要用于在应用程序前后台切换时,根据不同的场景切换合适的垃圾回收器。

6.2.3 HeapTrimTask

GC 完成后,如果需要将堆中空闲的内存归还给内核,则会执行此任务。这样可以减少应用程序占用的内存,从而提高系统的整体性能。

代码语言:javascript
复制
// Heap::HeapTrimTask类,继承自HeapTask,表示堆内存整理任务
class Heap::HeapTrimTask : public HeapTask {
 public:
  // 构造函数,接收一个增量时间(delta_time),计算出目标运行时间
  explicit HeapTrimTask(uint64_t delta_time) : HeapTask(NanoTime() + delta_time) { }
  
  // 重写Run方法,执行堆内存整理任务
  void Run(Thread* self) override {
    // 获取当前运行时的堆
    gc::Heap* heap = Runtime::Current()->GetHeap();
    // 整理堆内存
    heap->Trim(self);
    // 清除待处理的内存整理任务
    heap->ClearPendingTrim(self);
  }
};

Heap::HeapTrimTask 类是一个继承自 HeapTask 的任务类,用于表示堆内存整理任务。在构造函数中,需要传入一个增量时间(delta_time),然后计算出目标运行时间。

Run 方法是执行堆内存整理任务的核心逻辑。首先,获取当前运行时的堆。接着,调用 heap->Trim(self) 方法整理堆内存。整理堆内存的主要目的是将堆中空闲的内存归还给内核,从而减少应用程序占用的内存,提高系统的整体性能。最后,调用 heap->ClearPendingTrim(self) 方法清除待处理的内存整理任务。

6.2.4 TriggerPostForkCCGcTask

从 Android 8 开始,在启动时为了避免 GC 操作,系统会执行此任务,将 HeapTaskDaemon 线程阻塞 2 秒。这可以减少启动过程中的 GC 开销,从而提高应用程序的启动速度。

代码语言:javascript
复制
// Run a gc if we haven't run one since initial_gc_num. This forces processes to
// reclaim memory allocated during startup, even if they don't do much
// allocation post startup. If the process is actively allocating and triggering
// GCs, or has moved to the background and hence forced a GC, this does nothing.
class Heap::TriggerPostForkCCGcTask : public HeapTask {
 public:
  // 构造函数,接收目标运行时间和初始GC序列号
  explicit TriggerPostForkCCGcTask(uint64_t target_time, uint32_t initial_gc_num) :
      HeapTask(target_time), initial_gc_num_(initial_gc_num) {}
      
  // 重写Run方法,执行启动后的GC任务
  void Run(Thread* self) override {
    // 获取当前运行时的堆
    gc::Heap* heap = Runtime::Current()->GetHeap();
    // 如果当前GC序列号等于初始GC序列号,说明没有进行过GC
    if (heap->GetCurrentGcNum() == initial_gc_num_) {
      // 如果启用了日志记录所有GC操作
      if (kLogAllGCs) {
        LOG(INFO) << "Forcing GC for allocation-inactive process";
      }
      // 请求执行并发GC
      heap->RequestConcurrentGC(self, kGcCauseBackground, false, initial_gc_num_);
    }
  }
  
 private:
  uint32_t initial_gc_num_;  // 初始GC序列号
};

Heap::TriggerPostForkCCGcTask 类是一个继承自 HeapTask 的任务类,用于在应用启动后触发一次 GC 任务。在构造函数中,需要传入目标运行时间和初始 GC 序列号。

Run 方法是执行启动后的 GC 任务的核心逻辑。首先,获取当前运行时的堆。接着,检查当前 GC 序列号是否等于初始 GC 序列号。如果等于,说明没有进行过 GC,此时需要强制执行一次 GC 任务,以回收启动期间分配的内存。最后,调用 heap->RequestConcurrentGC(self, kGcCauseBackground, false, initial_gc_num_) 方法请求执行并发 GC。这个任务主要用于在应用启动后回收启动期间分配的内存,提高系统的整体性能。

6.2.5 ReduceTargetFootprintTask

TriggerPostForkCCGcTask 配合使用,用于在启动时减少 GC 的开销。

代码语言:javascript
复制
// Heap::ReduceTargetFootprintTask类,继承自HeapTask,表示减小目标内存占用任务
class Heap::ReduceTargetFootprintTask : public HeapTask {
 public:
  // 构造函数,接收目标运行时间、新的目标内存占用大小和初始GC序列号
  explicit ReduceTargetFootprintTask(uint64_t target_time, size_t new_target_sz,
                                     uint32_t initial_gc_num) :
      HeapTask(target_time), new_target_sz_(new_target_sz), initial_gc_num_(initial_gc_num) {}
      
  // 重写Run方法,执行减小目标内存占用任务
  void Run(Thread* self) override {
    gc::Heap* heap = Runtime::Current()->GetHeap();
    MutexLock mu(self, *(heap->gc_complete_lock_));
    // 如果自初始GC序列号以来没有进行过GC,并且没有正在运行的收集器
    if (heap->GetCurrentGcNum() == initial_gc_num_
        && heap->collector_type_running_ == kCollectorTypeNone) {
      // 获取当前目标内存占用
      size_t target_footprint = heap->target_footprint_.load(std::memory_order_relaxed);
      // 如果当前目标内存占用大于新的目标内存占用
      if (target_footprint > new_target_sz_) {
        // 使用CompareAndSetStrongRelaxed原子操作更新目标内存占用
        if (heap->target_footprint_.CompareAndSetStrongRelaxed(target_footprint, new_target_sz_)) {
          // 设置默认的并发启动字节
          heap->SetDefaultConcurrentStartBytesLocked();
        }
      }
    }
  }
 private:
  size_t new_target_sz_;     // 新的目标内存占用大小
  uint32_t initial_gc_num_;  // 初始GC序列号
};

Heap::ReduceTargetFootprintTask 类是一个继承自 HeapTask 的任务类,用于表示减小目标内存占用任务。在构造函数中,需要传入目标运行时间、新的目标内存占用大小和初始 GC 序列号。

Run 方法是执行减小目标内存占用任务的核心逻辑。首先,获取当前运行时的堆。接着,检查自初始 GC 序列号以来是否进行过 GC,并且没有正在运行的收集器。如果满足条件,则获取当前目标内存占用,如果当前目标内存占用大于新的目标内存占用,使用原子操作更新目标内存占用,并设置默认的并发启动字节。这个任务主要用于在应用启动后减少内存占用,提高系统的整体性能。

6.2.6 ClearedReferenceTask

在对象回收时,会执行此任务。任务中调用 Java 层的 ReferenceQueue.add 方法,将被回收对象引用添加到 ReferenceQueue 队列中。LeakCanary 就是通过这个队列来判断内存泄漏的。

代码语言:javascript
复制
// ClearedReferenceTask类,继承自HeapTask,表示清除引用任务
class ClearedReferenceTask : public HeapTask {
 public:
  // 构造函数,接收一个清除引用的全局引用
  explicit ClearedReferenceTask(jobject cleared_references)
      : HeapTask(NanoTime()), cleared_references_(cleared_references) {
  }
  
  // 重写Run方法,执行清除引用任务
  void Run(Thread* thread) override {
    // 获取当前线程的对象访问
    ScopedObjectAccess soa(thread);
    // 调用Java层的ReferenceQueue.add方法,将被回收对象引用添加到ReferenceQueue队列中
    WellKnownClasses::java_lang_ref_ReferenceQueue_add->InvokeStatic<'V', 'L'>(
        thread, soa.Decode<mirror::Object>(cleared_references_));
    // 删除全局引用
    soa.Env()->DeleteGlobalRef(cleared_references_);
  }

 private:
  const jobject cleared_references_;  // 清除引用的全局引用
};

ClearedReferenceTask 类是一个继承自 HeapTask 的任务类,用于表示清除引用任务。在构造函数中,需要传入一个清除引用的全局引用。

Run 方法是执行清除引用任务的核心逻辑。首先,获取当前线程的对象访问(ScopedObjectAccess)。接着,调用 Java 层的 ReferenceQueue.add 方法,将被回收对象引用添加到 ReferenceQueue 队列中。最后,删除全局引用。这个任务主要用于在对象回收时,将被回收对象引用添加到 ReferenceQueue 队列中。这有助于检测内存泄漏,例如 LeakCanary 就是通过这个队列来判断内存泄漏的。

6.2.7 小结

这些 HeapTask 任务在 Android 系统中的内存管理中起到了关键作用,它们共同确保了应用程序在运行过程中能够高效地回收内存,提高系统性能,同时避免内存泄漏。

6.3 TaskProcessor:HeapTask如何被执行

在 Android GC(垃圾回收)中,TaskProcessor 负责处理和执行堆任务,如垃圾回收、内存整理等。以下是 TaskProcessor 在 Android GC 中的作用、原理和调用链。

6.3.1 TaskProcessor的作用
  • TaskProcessor 主要用于处理和执行堆任务,如垃圾回收、内存整理等。
  • 它提供了添加任务、获取任务等方法,方便 GC 模块将任务添加到任务队列中,并在合适的时机执行这些任务。
6.3.2 TaskProcessor原理
  • TaskProcessor 类维护了一个任务队列 tasks_,用于存储待处理的堆任务。任务队列按照任务的目标运行时间排序,确保按照任务的优先级执行。
  • AddTask 方法用于将任务添加到任务队列中,并通知堆任务守护线程(HeapTaskDaemon)有新任务到来。
  • GetTask 方法用于从任务队列中获取一个任务。它会根据任务的目标运行时间判断是否可以执行任务,如果可以执行,则从任务队列中移除任务并返回以便执行;否则,等待直到达到任务的目标运行时间。
  • 堆任务守护线程(HeapTaskDaemon)负责调用 TaskProcessorGetTask 方法获取任务,并执行任务。当任务队列为空时,守护线程会等待任务队列中有新任务到来。

通过 TaskProcessor,Android GC 可以将堆任务按照优先级排序并执行,从而实现垃圾回收、内存整理等功能。

我们看一下GetTask的实现:

代码语言:javascript
复制
HeapTask* TaskProcessor::GetTask(Thread* self) {
  // 更改线程状态为kWaitingForTaskProcessor
  ScopedThreadStateChange tsc(self, ThreadState::kWaitingForTaskProcessor);
  // 获取锁
  MutexLock mu(self, lock_);
  while (true) {
    // 如果任务队列为空
    if (tasks_.empty()) {
      // 如果处理器已停止运行,则返回nullptr
      if (!is_running_) {
        return nullptr;
      }
      // 等待任务队列中有新任务到来
      cond_.Wait(self);
    } else {
      // 任务队列非空,查看队首任务,判断是否可以执行
      const uint64_t current_time = NanoTime();
      HeapTask* task = *tasks_.begin();
      // 获取任务的目标运行时间
      uint64_t target_time = task->GetTargetRunTime();
      // 如果处理器已停止运行,或者当前时间已经超过任务的目标运行时间,则执行任务
      if (!is_running_ || target_time <= current_time) {
        // 从任务队列中移除任务
        tasks_.erase(tasks_.begin());
        // 返回任务以便执行
        return task;
      }
      DCHECK_GT(target_time, current_time);
      // 计算等待时间
      const uint64_t delta_time = target_time - current_time;
      const uint64_t ms_delta = NsToMs(delta_time);
      const uint64_t ns_delta = delta_time - MsToNs(ms_delta);
      // 等待直到达到任务的目标运行时间
      cond_.TimedWait(self, static_cast<int64_t>(ms_delta), static_cast<int32_t>(ns_delta));
    }
  }
  UNREACHABLE();
}

TaskProcessor::GetTask() 方法用于从任务处理器中获取一个任务。首先,更改线程状态为 kWaitingForTaskProcessor 并获取锁。接着,判断任务队列是否为空,如果为空,则等待任务队列中有新任务到来;如果非空,则查看队首任务,判断是否可以执行。如果任务处理器已停止运行,或者当前时间已经超过任务的目标运行时间,则从任务队列中移除任务并返回任务以便执行;否则,等待直到达到任务的目标运行时间。这个方法主要用于从任务处理器中获取一个任务,等待任务到来并根据任务的目标运行时间判断是否可以执行。

6.3.3 TaskProcessor调用链
  • TaskProcessor 类在 art/runtime/gc/task_processor.h 中定义,包含了一个任务队列 tasks_,用于存储待处理的堆任务。
  • art/runtime/gc/heap.cc 中,Heap 类的构造函数会创建一个 TaskProcessor 实例,用于执行垃圾回收任务。
  • Heap 类的各种 GC 请求方法(如 RequestConcurrentGCRequestGC 等)中,会创建相应的垃圾回收任务(如 ConcurrentGCTaskGcTask 等),并通过 TaskProcessor 实例的 AddTask 方法将任务添加到任务队列中。
  • HeapTaskDaemon 类(位于 art/runtime/gc/heap_task_daemon.cc)中,runInternal 方法会调用 TaskProcessorGetTask 方法获取一个任务,并执行该任务。

七、总结

理解Android垃圾回收机制有助于我们编写更高效的代码,提高应用性能。通过减少对象创建、使用弱引用和软引用、避免内存泄漏以及优化数据结构,我们可以降低垃圾回收的频率和开销,从而提高应用的响应速度和稳定性。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 陆业聪 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、内存分配
  • 二、垃圾回收触发条件
  • 三、GC算法
    • 3.1 Dalvik虚拟机的GC算法
      • 3.2 ART的GC算法
      • 四、优化GC性能
      • 五、监控GC耗时情况
      • 六、Android运行时的垃圾回收器:HeapTask
        • 6.1 HeapTask简介
          • 6.2 HeapTask的子类类型
            • 6.2.1 ConcurrentGCTask
            • 6.2.2 CollectorTransitionTask
            • 6.2.3 HeapTrimTask
            • 6.2.4 TriggerPostForkCCGcTask
            • 6.2.5 ReduceTargetFootprintTask
            • 6.2.6 ClearedReferenceTask
            • 6.2.7 小结
          • 6.3 TaskProcessor:HeapTask如何被执行
            • 6.3.1 TaskProcessor的作用
            • 6.3.2 TaskProcessor原理
            • 6.3.3 TaskProcessor调用链
        • 七、总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档