♻️ Dart VM 垃圾回收

源码级深度解析

基于 Dart SDK 源码 · heap.cc / scavenger.cc / marker.cc / pages.cc
2026-03-04 | 每日技术深度解读

📖 概述

Dart VM 使用分代垃圾回收策略,结合多种 GC 算法实现高效的内存管理。

核心组件:

  • Scavenger - 新生代复制式收集器
  • PageSpace - 老年代页面空间
  • GCMarker - 并发/并行标记器
  • GCSweeper - 清扫器/压缩器

🏗️ 堆结构

class Heap {
  Scavenger new_space_;   // 新生代 (复制收集)
  PageSpace old_space_;   // 老年代 (标记-清除)
  
  enum Space { kNew, kOld, kCode };
};
┌─────────────────────────────────────────┐ │ Heap │ ├─────────────────────────────────────────┤ │ New Space (Scavenger) │ │ ├── SemiSpace (to) │ │ └── SemiSpace (from) │ ├─────────────────────────────────────────┤ │ Old Space (PageSpace) │ │ ├── Regular Pages │ │ ├── Executable Pages │ │ ├── Large Pages │ │ └── Image Pages │ └─────────────────────────────────────────┘

📊 分代假说

弱分代假说:大多数对象朝生夕死
强分代假说:熬过越多次 GC 的对象越难以消亡

Dart VM 的应用:

  • 新对象分配在 New Space
  • 存活多次的对象晋升到 Old Space
  • 不同代使用不同的 GC 算法

🔧 GC 类型

enum class GCType {
  kScavenge,           // 新生代复制收集
  kEvacuate,           // 紧急疏散
  kStartConcurrentMark, // 启动并发标记
  kMarkSweep,          // 标记-清除
  kMarkCompact,        // 标记-压缩
};
类型目标空间特点
ScavengeNew复制存活对象,速度快
MarkSweepOld标记清除,并发执行
MarkCompactOld压缩碎片,完整GC

⚡ Scavenge - 新生代收集

Scavenge 使用 Cheney 复制算法,将存活对象从 from-space 复制到 to-space。
void Scavenger::Scavenge(Thread* thread, 
                         GCType type, 
                         GCReason reason) {
  // 1. 翻转半空间
  SemiSpace* from = Prologue(reason);
  
  // 2. 复制存活对象
  ScavengeRoots();
  ScavengeSurvivors();
  
  // 3. 处理弱引用
  ProcessWeak();
  
  // 4. 清理 from-space
  Epilogue(from);
}

🔄 Scavenge 执行流程

┌──────────┐ ┌──────────┐ ┌──────────┐ │ Prologue │───▶│ Roots │───▶│Survivors │ └──────────┘ └──────────┘ └──────────┘ │ │ │ 翻转空间 │ 复制/晋升 ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ from │◀───│Weak Proc │◀───│Promotion │ └──────────┘ └──────────┘ └──────────┘ │ │ 释放 ▼ ┌──────────┐ │ Epilogue │ └──────────┘

📐 Cheney 复制算法

ObjectPtr ScavengeObject(ObjectPtr obj) {
  uword header = ReadHeaderRelaxed(obj);
  
  if (IsForwarding(header)) {
    // 已转发,返回新地址
    return ForwardedObj(header);
  }
  
  // 分配新空间
  uword new_addr = TryAllocateCopy(size);
  
  // 复制对象
  objcpy(new_addr, raw_addr, size);
  
  // 安装转发指针
  InstallForwardingPointer(addr, &header, 
                           ForwardingHeader(new_obj));
  
  return new_obj;
}

🔀 转发指针 (Forwarding Pointer)

利用对象头部的 CardRememberedBit 位区分对象是否已转发。
enum {
  kForwardingMask = UntaggedObject::CardRememberedBit::mask(),
  kNotForwarded = 0,
  kForwarded = kForwardingMask,
};

static bool IsForwarding(uword header) {
  return (header & kForwardingMask) == kForwarded;
}

static ObjectPtr ForwardedObj(uword header) {
  return static_cast<ObjectPtr>(header);
}

🚀 对象晋升 (Promotion)

当对象在多次 Scavenge 中存活,或 to-space 空间不足时,对象会被晋升到老年代。
ObjectPtr ScavengeObject(ObjectPtr obj) {
  // 检查是否应该晋升
  if (!Page::Of(obj)->IsSurvivor(raw_addr)) {
    // 新对象,复制到 to-space
    new_addr = TryAllocateCopy(size);
  }
  
  if (new_addr == 0) {
    // Survivor 或空间不足,尝试晋升
    new_addr = page_space_->TryAllocatePromoLocked(freelist, size);
    
    if (new_addr == 0) {
      // 晋升失败,强制复制到 to-space
      new_addr = TryAllocateCopy(size);
    }
  }
}

📈 晋升阈值

DEFINE_FLAG(int, early_tenuring_threshold, 66,
  "When more than this percentage of promotion "
  "candidates survive, promote all survivors.");

void Epilogue(SemiSpace* from) {
  double avg_frac = stats_history_.Get(0)
                    .PromoCandidatesSuccessFraction();
  
  if (stats_history_.Size() >= 2) {
    avg_frac += 0.5 * stats_history_.Get(1)
                       .PromoCandidatesSuccessFraction();
    avg_frac /= 1.5;
  }
  
  early_tenure_ = avg_frac >= 
                  (FLAG_early_tenuring_threshold / 100.0);
}

🔍 Mark-Sweep - 老年代收集

老年代使用 三色标记-清除 算法,支持并发增量标记。
void PageSpace::CollectGarbage(Thread* thread, 
                               bool compact, 
                               bool finalize) {
  // 1. 标记阶段
  marker_->MarkObjects(this);
  
  // 2. 清除阶段
  SweepLarge();
  Sweep(/*exclusive*/ true);
  
  // 3. 可选压缩
  if (compact) {
    Compact(thread);
  }
}

🎯 标记阶段

void GCMarker::MarkObjects(PageSpace* page_space) {
  Prologue();
  
  // 并行标记任务
  for (intptr_t i = 0; i < FLAG_marker_tasks; ++i) {
    tasks.Append(new ParallelMarkTask(
      this, isolate_group_, 
      &old_marking_stack_, 
      barrier, visitor, &num_busy));
  }
  
  // 执行任务
  safepoint_handler->RunTasks(&tasks);
  
  // 弱引用处理
  IterateWeakRoots(thread);
  
  Epilogue();
}

🎨 三色标记算法

颜色定义:

  • 白色 - 未访问
  • 灰色 - 已标记,子对象未处理
  • 黑色 - 已标记,子对象已处理

不变式:

  • 黑色对象不能直接指向白色对象
  • 通过写屏障维护
bool MarkObject(ObjectPtr obj) {
  if (obj->IsImmediateObject()) return false;
  
  // 尝试获取标记位
  if (obj->untag()->TryAcquireMarkBit()) {
    old_work_list_.Push(obj);  // 加入工作列表
  }
  return false;
}

🔄 并发标记 (Concurrent Marking)

标记过程与应用线程并发执行,通过写屏障保证正确性。
void GCMarker::StartConcurrentMark(PageSpace* page_space) {
  isolate_group_->EnableIncrementalBarrier(
      &old_marking_stack_, 
      &new_marking_stack_, 
      &deferred_marking_stack_);
  
  // 启动多个并发标记任务
  for (intptr_t i = 0; i < num_tasks; i++) {
    Dart::thread_pool()->Run<ConcurrentMarkTask>(
        this, isolate_group_, page_space, visitor);
  }
}

⏱️ 增量标记 (Incremental Marking)

将标记工作分片执行,减少单次暂停时间。
void IncrementalMarkWithSizeBudget(intptr_t size) {
  const intptr_t kMinimumMarkingStep = KB;
  if (size < kMinimumMarkingStep) return;
  
  MarkingVisitor visitor(...);
  visitor.ProcessOldMarkingStack(size);
  
  marked_bytes_ += visitor.marked_bytes();
  marked_micros_ += visitor.marked_micros();
}

void IncrementalMarkWithTimeBudget(int64_t deadline) {
  visitor.ProcessOldMarkingStackUntil(deadline);
}

🛡️ 写屏障 (Write Barrier)

写屏障用于在并发标记期间维护三色不变式
// 当写入指针时触发
void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
  for (ObjectPtr* current = first; current <= last; current++) {
    ObjectPtr obj = LoadPointerIgnoreRace(current);
    
    if (MarkObject(obj)) {
      has_evacuation_candidate_ = true;
    }
  }
  
  // 更新 Store Buffer
  if (has_evacuation_candidate_) {
    if (obj->untag()->TryAcquireRememberedBit()) {
      thread->StoreBufferAddObjectGC(obj);
    }
  }
}

📦 Store Buffer

Store Buffer 记录跨代引用(老年代指向新生代),用于 Scavenge 时的根集扫描。
void IterateStoreBuffers(ScavengerVisitor* visitor) {
  StoreBuffer* store_buffer = 
      heap_->isolate_group()->store_buffer();
  
  for (;;) {
    StoreBufferBlock* pending = blocks_;
    if (pending == nullptr) break;
    
    while (!pending->IsEmpty()) {
      ObjectPtr obj = pending->Pop();
      obj->untag()->ClearRememberedBit();
      visitor->VisitingOldObject(obj);
      visitor->ProcessObject(obj);
    }
  }
}

🃏 Card Remembered Set

对于大数组,使用卡片标记减少 Store Buffer 压力。
intptr_t VisitCards(ArrayPtr obj) {
  Page* page = Page::Of(obj);
  
  for (intptr_t i = 0, n = page->card_table_size(); 
       i < n; i++) {
    CompressedObjectPtr* card_from = ...;
    CompressedObjectPtr* card_to = ...;
    
    VisitCompressedPointers(heap_base, card_from, card_to);
    
    if (has_evacuation_candidate_) {
      page->RememberCard(card_from);
    }
  }
}

🧹 清除阶段 (Sweep)

void PageSpace::Sweep(bool exclusive) {
  GCSweeper sweeper;
  
  while (sweep_regular_ != nullptr) {
    Page* page = sweep_regular_;
    sweep_regular_ = page->next();
    
    // 清扫页面,回收未标记对象
    bool page_in_use = sweeper.SweepPage(page, freelist);
    
    if (!page_in_use) {
      // 页面为空,释放
      page->Deallocate();
    } else {
      // 页面有存活对象,加入页面列表
      AddPageLocked(page);
    }
  }
}

🔄 并发清除 (Concurrent Sweep)

清除过程可以并发执行,不阻塞应用线程。
void PageSpace::ConcurrentSweep(IsolateGroup* isolate_group) {
  GCSweeper::SweepConcurrent(isolate_group);
}

// 页面状态
enum Phase {
  kDone,                    // 空闲
  kMarking,                 // 标记中
  kAwaitingFinalization,    // 等待最终化
  kSweepingLarge,           // 清扫大页
  kSweepingRegular,         // 清扫常规页
};

🗜️ Mark-Compact

当堆碎片化严重时,执行压缩操作,将存活对象移动到连续空间。
void PageSpace::Compact(Thread* thread) {
  GCCompactor compactor(thread, heap_);
  compactor.Compact(pages_, &freelists_[kDataFreelist], 
                    &pages_lock_);
  
  if (FLAG_verify_after_gc) {
    heap_->VerifyGC("Verifying after compacting", 
                    kForbidMarked);
  }
}

bool ShouldPerformIdleMarkCompact(int64_t deadline) {
  const intptr_t excess = capacity - used - 2 * Page::kPageSize;
  const double excess_ratio = excess / capacity;
  return excess_ratio > 0.05;  // 碎片率 > 5%
}

📊 压缩算法流程

┌─────────────┐ │ 标记阶段 │ 标记所有存活对象 └──────┬──────┘ │ ▼ ┌─────────────┐ │ 计算新地址 │ 为每个存活对象计算目标地址 └──────┬──────┘ │ ▼ ┌─────────────┐ │ 更新引用 │ 更新所有指向移动对象的指针 └──────┬──────┘ │ ▼ ┌─────────────┐ │ 移动对象 │ 将对象复制到新位置 └─────────────┘

🔗 空闲链表 (Free List)

class FreeList {
  // 小对象:固定大小桶
  FreeListElement* free_lists_[kNumLists];
  
  // 大对象:独立链表
  FreeListElement* free_list_;
  
  uword TryAllocate(intptr_t size) {
    if (size <= kMaxSmallAlloc) {
      // 从对应桶分配
      int index = IndexForSize(size);
      return TryAllocateSmall(index, size);
    } else {
      // 从大对象链表查找
      return TryAllocateLarge(size);
    }
  }
};

📄 页面管理

class PageSpace {
  Page* pages_;          // 常规数据页
  Page* exec_pages_;     // 可执行代码页
  Page* large_pages_;    // 大对象页
  Page* image_pages_;    // 镜像页
  
  Page* AllocatePage(bool is_exec) {
    Page* page = Page::Allocate(Page::kPageSize, flags);
    if (is_exec) {
      AddExecPageLocked(page);
    } else {
      AddPageLocked(page);
    }
    return page;
  }
};

📦 TLAB (Thread Local Allocation Buffer)

每个线程拥有独立的分配缓冲区,避免锁竞争。
class Thread {
  uword top_;    // 当前分配指针
  uword end_;    // 缓冲区结束位置
};

uword TryAllocateCopy(intptr_t size) {
  if (tail_ != nullptr) {
    uword result = tail_->top_;
    uword new_top = result + size;
    
    if (new_top <= tail_->end_) {
      tail_->top_ = new_top;
      return result;  // 快速路径,无锁
    }
  }
  return TryAllocateCopySlow(size);
}

🛑 Safepoint

GC 需要所有线程到达安全点后才能执行,确保堆状态一致。
class GcSafepointOperationScope {
  GcSafepointOperationScope(Thread* thread) {
    isolate_group()->safepoint_handler()
        ->SafepointThreads(thread, SafepointLevel::kGC);
  }
  
  ~GcSafepointOperationScope() {
    isolate_group()->safepoint_handler()
        ->ResumeThreads(thread, SafepointLevel::kGC);
  }
};

void CollectGarbage(Thread* thread, ...) {
  GcSafepointOperationScope safepoint(thread);
  // 执行 GC...
}

⏰ GC 触发时机

enum class GCReason {
  kNewSpace,      // 新生代空间不足
  kStoreBuffer,   // Store Buffer 溢出
  kPromotion,     // 晋升触发
  kOldSpace,      // 老年代空间不足
  kFinalize,      // 最终化标记
  kFull,          // 完整 GC
  kExternal,      // 外部内存分配
  kIdle,          // 空闲时 GC
  kDestroyed,     // Isolate 销毁
  kDebugging,     // 调试触发
  kCatchUp,       // 追赶模式
};

💤 空闲 GC (Idle GC)

在应用空闲时执行 GC,减少用户感知的暂停。
void Heap::NotifyIdle(int64_t deadline) {
  GcSafepointOperationScope safepoint(thread);
  
  // 空闲 Scavenge
  if (new_space_.ShouldPerformIdleScavenge(deadline)) {
    CollectNewSpaceGarbage(thread, GCType::kScavenge, 
                           GCReason::kIdle);
  }
  
  // 空闲 Mark-Compact
  if (old_space_.ShouldPerformIdleMarkCompact(deadline)) {
    CollectOldSpaceGarbage(thread, GCType::kMarkCompact, 
                           GCReason::kIdle);
  }
}

🔗 弱引用处理

GC 需要特殊处理弱引用,避免保留本应回收的对象。
  • WeakProperty - 弱键值对
  • WeakReference - 弱引用
  • WeakArray - 弱数组
  • FinalizerEntry - 终结器条目

🎯 Finalizer

intptr_t ProcessFinalizerEntry(FinalizerEntryPtr entry) {
    delayed_.finalizer_entries.Enqueue(entry);
    
    // 只访问 token 和 next
    MarkObject(entry->untag()->token_);
    MarkObject(entry->untag()->next_);
    
    return entry->untag()->HeapSize();
}

void MournFinalizerEntries() {
    FinalizerEntryPtr current = delayed_.finalizer_entries.Release();
    while (current != FinalizerEntry::null()) {
        MournFinalizerEntry(this, current);
        current = current->untag()->next_seen_by_gc();
    }
}

🔑 WeakProperty

intptr_t ProcessWeakProperty(WeakPropertyPtr weak) {
  ObjectPtr key = weak->untag()->key();
  
  if (key->IsHeapObject() && !key->untag()->IsMarked()) {
    // 键未标记,入队延迟处理
    delayed_.weak_properties.Enqueue(weak);
    return weak->untag()->HeapSize();
  }
  
  // 键已标记,正常访问
  return weak->untag()->VisitPointersNonlocal(this);
}

void MournWeakProperties() {
  // 清除键值对
  weak->untag()->key_ = Object::null();
  weak->untag()->value_ = Object::null();
}

👁️ WeakReference

intptr_t ProcessWeakReference(WeakReferencePtr weak) {
  ObjectPtr target = weak->untag()->target();
  
  if (target->IsHeapObject() && !target->untag()->IsMarked()) {
    // 目标未标记,入队延迟处理
    delayed_.weak_references.Enqueue(weak);
  }
  
  // 始终访问类型参数
  MarkObject(weak->untag()->type_arguments_);
  return weak->untag()->HeapSize();
}

void MournWeakReferences() {
  // 如果目标被回收,置空
  ForwardOrSetNullIfCollected(weak, &weak->untag()->target_);
}

📊 WeakArray

intptr_t ProcessWeakArray(WeakArrayPtr weak) {
  // 所有 WeakArray 入队延迟处理
  delayed_.weak_arrays.Enqueue(weak);
  return weak->untag()->HeapSize();
}

void MournWeakArrays() {
  WeakArrayPtr current = delayed_.weak_arrays.Release();
  while (current != WeakArray::null()) {
    intptr_t length = Smi::Value(current->untag()->length());
    for (intptr_t i = 0; i < length; i++) {
      // 被回收的元素置空
      ForwardOrSetNullIfCollected(
          current, ¤t->untag()->data()[i]);
    }
    current = current->untag()->next_seen_by_gc();
  }
}

📊 内存统计

struct SpaceUsage {
  intptr_t capacity_in_words;
  intptr_t used_in_words;
  intptr_t external_in_words;
};

class GCStats {
  intptr_t num_;          // GC 次数
  GCType type_;           // GC 类型
  GCReason reason_;       // GC 原因
  
  Data before_;           // GC 前状态
  Data after_;            // GC 后状态
};

📝 GC 日志

void PrintStats() {
  OS::PrintErr(
    "[ GC isolate | space (reason) | GC# | time | "
    "new gen used/cap/ext | old gen used/cap/ext ]\n"
    "[ %-13s, %11s(%12s), %4" Pd ", %5.1fms, "
    "%5.1f/%5.1f/%3.1f MB, %6.1f/%6.1f/%5.1f MB ]\n",
    isolate_name, GCTypeToString(type_), 
    GCReasonToString(reason_),
    num_, duration_ms,
    new_before, new_capacity, new_external,
    old_before, old_capacity, old_external);
}

✅ 堆验证

bool Heap::VerifyGC(const char* msg, 
                    MarkExpectation expect) {
  // 创建已分配对象集合
  ObjectSet* allocated = CreateAllocatedObjectSet(zone, expect);
  
  // 验证所有指针指向有效对象
  VerifyPointersVisitor visitor(isolate_group_, allocated, msg);
  VisitObjectPointers(&visitor);
  
  return true;
}

// 验证选项
DEFINE_FLAG(bool, verify_before_gc, false, 
            "Verify heap before GC");
DEFINE_FLAG(bool, verify_after_gc, false, 
            "Verify heap after GC");

⚠️ OOM 处理

当内存耗尽时,Dart VM 会预留OOM 保留空间用于抛出异常。
uword Heap::AllocateOld(Thread* thread, intptr_t size, 
                        bool is_exec) {
  // 尝试各种 GC 策略
  CollectOldSpaceGarbage(thread, GCType::kMarkSweep, ...);
  
  // 最后尝试强制增长
  addr = old_space_.TryAllocate(size, is_exec, kForceGrowth);
  
  if (addr == 0) {
    // 释放 OOM 保留空间
    old_space_.TryReleaseReservation();
    
    OS::PrintErr("Exhausted heap space, size=%" Pd "\n", size);
    isolate_group_->set_has_seen_oom(true);
  }
  return addr;
}

⚡ 性能调优

通过调整 GC 参数,优化应用性能。

新生代调优:

  • 增大新生代减少 Scavenge 频率
  • 调整晋升阈值

老年代调优:

  • 启用并发标记
  • 调整增长策略

🔧 调优参数

参数默认值说明
new_gen_semi_initial_size-新生代初始大小
new_gen_garbage_threshold90垃圾占比阈值
new_gen_growth_factor2新生代增长因子
early_tenuring_threshold66早期晋升阈值
old_gen_growth_space_ratio20老年代增长空间比
old_gen_growth_time_ratio3老年代增长时间比
concurrent_marktrue启用并发标记
marker_tasks2标记任务数

🔀 并行 GC

Dart VM 支持多线程并行执行 GC,充分利用多核 CPU。
void RunParallelGC() {
  const intptr_t num_tasks = 
      heap_->new_space()->NumScavengeWorkers();
  
  ThreadBarrier* barrier = 
      new ThreadBarrier(num_tasks, /*initial=*/1);
  
  IntrusiveDList<SafepointTask> tasks;
  for (intptr_t i = 0; i < num_tasks; i++) {
    tasks.Append(new ParallelMarkTask(...));
  }
  
  safepoint_handler->RunTasks(&tasks);
}

🎯 标记任务

class ParallelMarkTask : public SafepointTask {
  void RunEnteredIsolateGroup() override {
    // 阶段 1: 标记根和标记栈
    num_busy_->fetch_add(1u);
    marker_->IterateRoots(visitor_);
    
    do {
      visitor_->DrainMarkingStack();
    } while (visitor_->WaitForWork(num_busy_));
    
    // 阶段 2: 延迟标记
    visitor_->ProcessDeferredMarking();
    
    // 阶段 3: 弱引用处理
    visitor_->MournWeakProperties();
    visitor_->MournWeakReferences();
    marker_->IterateWeakRoots(thread);
  }
};

🧹 清除任务

class ParallelSweepTask : public SafepointTask {
  void RunEnteredIsolateGroup() override {
    // 清扫可执行页面
    old_space_->SweepExecutable();
    
    // 清扫新生代页面
    if (!new_space_is_swept_) {
      old_space_->SweepNew();
    }
  }
};

void Sweep(bool exclusive) {
  GCSweeper sweeper;
  
  // 轮询分片,均匀分配到各个空闲链表
  shard = (shard + 1) % num_shards;
  FreeList* freelist = DataFreeList(shard);
  sweeper.SweepPage(page, freelist);
}

📸 堆快照

当发生 OOM 时,可以生成堆快照用于内存分析。
DEFINE_FLAG(charp, heap_snapshot_on_oom, nullptr,
  "Write a heap snapshot after OOM");

void OnOOM() {
#if defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
  if (FLAG_heap_snapshot_on_oom != nullptr) {
    FileHeapSnapshotWriter file_writer(
        thread, FLAG_heap_snapshot_on_oom, &successful);
    HeapSnapshotWriter writer(thread, &file_writer);
    writer.Write();
  }
#endif
}

🔬 内存分析工具

Dart DevTools:

  • 堆分析器
  • 内存快照
  • 分配追踪

VM Service API:

  • getAllocationProfile
  • getHeapMap
  • heap sampling
// 启用堆采样
void SetHeapSamplingData(ObjectPtr obj, void* data) {
  SetWeakEntry(obj, kHeapSamplingData, 
               reinterpret_cast<intptr_t>(data));
}

✨ 最佳实践

  • 避免大对象 - 大对象直接进入老年代
  • 减少对象创建 - 复用对象,减少 GC 压力
  • 及时释放引用 - 避免内存泄漏
  • 使用弱引用 - 缓存场景使用 WeakReference
  • 监控内存 - 定期检查内存使用情况
  • 避免循环引用 - 特别注意闭包和回调

❓ 常见问题

Q: 为什么 GC 频繁触发?
A: 可能是新生代太小或对象晋升太快
Q: 如何减少 GC 暂停?
A: 启用并发标记、增大堆空间、减少对象分配
Q: 内存不释放怎么办?
A: 检查是否有意外的强引用,使用 DevTools 分析

📈 性能监控

// 监控指标
void PrintMemoryUsageJSON(JSONObject* jsobj) {
  jsobj->AddProperty("type", "MemoryUsage");
  jsobj->AddProperty64("heapUsage", 
                       TotalUsedInWords() * kWordSize);
  jsobj->AddProperty64("heapCapacity", 
                       TotalCapacityInWords() * kWordSize);
  jsobj->AddProperty64("externalUsage", 
                       TotalExternalInWords() * kWordSize);
}

// RSS 监控
static void RecordRSS() {
  TimelineEvent* event = Timeline::GetGCStream()->StartEvent();
  event->FormatArgument(0, "value", "%" Pd, OS::CurrentRSS());
}

🎯 总结

Dart VM 的 GC 是一个复杂而精妙的系统,结合了多种算法和优化技术。
  • 分代收集 - 利用分代假说优化性能
  • 并发标记 - 减少应用暂停
  • 写屏障 - 保证并发正确性
  • 并行执行 - 充分利用多核
  • 空闲 GC - 智能利用空闲时间

📚 参考资料

  • 源码: dart-lang/sdk/runtime/vm/heap/
  • heap.cc - 堆管理核心
  • scavenger.cc - 新生代收集器
  • marker.cc - 标记器
  • pages.cc - 页面管理
  • heap.h - 堆接口定义

https://github.com/dart-lang/sdk