Android ART虚拟机 关键类

文章介绍了ART虚拟机中的HeapBitmap类,它是内存管理的关键部分,通过位图来表示对象引用,减少指针占用的内存空间。HeapBitmap包含连续空间位图和大对象位图,提供了设置、测试和遍历位图的函数。同时,文章提到了SpaceBitmap类,它是承载位图的实际数据结构,有按对象对齐和按页对齐两种模式。此外,还讨论了CardTable、RememberedSet和ModUnionTable在分代GC中的作用,用于跟踪跨代引用,优化垃圾收集效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

本文介绍ART虚拟机中的关键类,方便之后对下一篇ART的Heap构造函数更好的理解。此处几个类和dalvik一脉相承,也可以更好的理解dalvik里面的GC模块。

HeapBitmap

这块和dalvik类似,是用一块位图来表示内存对象的引用。

  • 如果创建1万个对象的话,那么这一万个对象的指针本身所占据的内存空间就很可观了。指针本身的长度根据CPU架构的不同导致是32位长或者是64位长。

  • 如何减少指针本身所占据的内存空间呢?ART采用的办法很简单,就是将对象的指针转换成一个位图里的索引,位图里的每一位指向一个唯一的指针。
    image.png

  • HeapBitmap:它其实是一个辅助类,它内部包含continuous_space_bitmaps_和large_object_bitmaps_两个成员。这两个成员都是vector数组,所存储的元素类型分别是ContinuousSpaceBitmap和LargeObjectBitmap。

art/runtime/gc/accounting/heap_bitmap.h

class HeapBitmap {
 public:
  void Clear(const mirror::Object* obj) REQUIRES(Locks::heap_bitmap_lock_);

  template<typename LargeObjectSetVisitor>
  bool Set(const mirror::Object* obj, const LargeObjectSetVisitor& visitor)
      SHARED_REQUIRES(Locks::mutator_lock_)
      REQUIRES(Locks::heap_bitmap_lock_) ALWAYS_INLINE;

  template<typename LargeObjectSetVisitor>
  bool AtomicTestAndSet(const mirror::Object* obj, const LargeObjectSetVisitor& visitor)
      SHARED_REQUIRES(Locks::mutator_lock_)
      REQUIRES(Locks::heap_bitmap_lock_) ALWAYS_INLINE;
  ContinuousSpaceBitmap* GetContinuousSpaceBitmap(const mirror::Object* obj) const;
  LargeObjectBitmap* GetLargeObjectBitmap(const mirror::Object* obj) const;

  void Walk(ObjectCallback* callback, void* arg)
      SHARED_REQUIRES(Locks::heap_bitmap_lock_);

  template <typename Visitor>
  void Visit(const Visitor& visitor)
      REQUIRES(Locks::heap_bitmap_lock_)
      SHARED_REQUIRES(Locks::mutator_lock_);

  // Find and replace a bitmap pointer, this is used by for the bitmap swapping in the GC.
  void ReplaceBitmap(ContinuousSpaceBitmap* old_bitmap, ContinuousSpaceBitmap* new_bitmap)
      REQUIRES(Locks::heap_bitmap_lock_);

  // Find and replace a object set pointer, this is used by for the bitmap swapping in the GC.
  void ReplaceLargeObjectBitmap(LargeObjectBitmap* old_bitmap, LargeObjectBitmap* new_bitmap)
      REQUIRES(Locks::heap_bitmap_lock_);

  explicit HeapBitmap(Heap* heap) : heap_(heap) {}

 private:
  const Heap* const heap_;

  void AddContinuousSpaceBitmap(ContinuousSpaceBitmap* bitmap);
  void RemoveContinuousSpaceBitmap(ContinuousSpaceBitmap* bitmap);
  void AddLargeObjectBitmap(LargeObjectBitmap* bitmap);
  void RemoveLargeObjectBitmap(LargeObjectBitmap* bitmap);

  // Bitmaps covering continuous spaces.
  std::vector<ContinuousSpaceBitmap*,
              TrackingAllocator<ContinuousSpaceBitmap*, kAllocatorTagHeapBitmap>>
      continuous_space_bitmaps_;

  // Sets covering discontinuous spaces.
  std::vector<LargeObjectBitmap*,
              TrackingAllocator<LargeObjectBitmap*, kAllocatorTagHeapBitmapLOS>>
      large_object_bitmaps_;

  friend class art::gc::Heap;
  friend class art::gc::collector::ConcurrentCopying;
};

SpaceBitmap

  • SpaceBitmap是一个模板类,模板参数表示内存地址对齐长度。
    取值为kObjectAlignment(值为8)表示按对象对齐,其对应的类型别名就是ContinuousSpaceBitmap。
    取值为kLargeObjectAlignment(值为4KB,一个内存页的大小)表示按页对齐,对应的类型别名为LargeObjectBitmap。
  • SpaceBitmap类才是真正承载位图的地方。 比如,它的heap_begin_成员代表所针对内存的基地址,位图本身的内存基地址由heap_begin_表示,位图的长度(包含多少位)则由bitmap_size_表示。

art/runtime/gc/accounting/space_bitmap.h

typedef SpaceBitmap<kObjectAlignment> ContinuousSpaceBitmap;
typedef SpaceBitmap<kLargeObjectAlignment> LargeObjectBitmap;

template<size_t kAlignment>
class SpaceBitmap {
 public:
  typedef void ScanCallback(mirror::Object* obj, void* finger, void* arg);
  typedef void SweepCallback(size_t ptr_count, mirror::Object** ptrs, void* arg);

  // Initialize a space bitmap so that it points to a bitmap large enough to cover a heap at
  // heap_begin of heap_capacity bytes, where objects are guaranteed to be kAlignment-aligned.
  static SpaceBitmap* Create(const std::string& name, uint8_t* heap_begin, size_t heap_capacity);

  // Initialize a space bitmap using the provided mem_map as the live bits. Takes ownership of the
  // mem map. The address range covered starts at heap_begin and is of size equal to heap_capacity.
  // Objects are kAlignement-aligned.
  static SpaceBitmap* CreateFromMemMap(const std::string& name, MemMap* mem_map,
                                       uint8_t* heap_begin, size_t heap_capacity);

  ~SpaceBitmap();

 private:
  SpaceBitmap(const std::string& name, MemMap* mem_map, uintptr_t* bitmap_begin, size_t bitmap_size, const void* heap_begin);

  // Backing storage for bitmap.
  std::unique_ptr<MemMap> mem_map_;

  // This bitmap itself, word sized for efficiency in scanning.
  uintptr_t* const bitmap_begin_;

  // Size of this bitmap.
  size_t bitmap_size_;

  // The base address of the heap, which corresponds to the word containing the first bit in the bitmap.
  const uintptr_t heap_begin_;

  // Name of this bitmap.
  std::string name_;
}

SpaceBitmap构造函数

art/runtime/gc/accounting/space_bitmap.cc

template<size_t kAlignment>
SpaceBitmap<kAlignment>::SpaceBitmap(const std::string& name, MemMap* mem_map, uintptr_t* bitmap_begin,
                                     size_t bitmap_size, const void* heap_begin)
    : mem_map_(mem_map), bitmap_begin_(bitmap_begin), bitmap_size_(bitmap_size),
      heap_begin_(reinterpret_cast<uintptr_t>(heap_begin)),
      name_(name) {
  CHECK(bitmap_begin_ != nullptr);
  CHECK_NE(bitmap_size, 0U);
}

template<size_t kAlignment>
SpaceBitmap<kAlignment>::~SpaceBitmap() {}

template<size_t kAlignment>
SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create(
    const std::string& name, uint8_t* heap_begin, size_t heap_capacity) {
  // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord.
  const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
  std::string error_msg;
  std::unique_ptr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size, PROT_READ | PROT_WRITE, false, false, &error_msg));

  return CreateFromMemMap(name, mem_map.release(), heap_begin, heap_capacity);
}

template<size_t kAlignment>
SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::CreateFromMemMap(
    const std::string& name, MemMap* mem_map, uint8_t* heap_begin, size_t heap_capacity) {
  CHECK(mem_map != nullptr);
  uintptr_t* bitmap_begin = reinterpret_cast<uintptr_t*>(mem_map->Begin());
  const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
  return new SpaceBitmap(name, mem_map, bitmap_begin, bitmap_size, heap_begin);
}

CardTable、RememberedSet、ModUnionTable

分代GC下,避免在回收新时代对象时将老年代对象也一并回收了,虚拟机需要主动记录哪些老年代对象引用了新生代的对象。所以,分代GC不仅要扫描新生代对应的root,还需要扫描这些纳入记录了的老年代对象。所以需要辅助的数据结构:

概念

  • RememberedSet:简单点说它就是一个容器类的数据结构。每一个引用了新生代对象的老年代对象都保存在RememberedSet中。其优点是精确,缺点是需要额外的内存空间来保存这些老年代对象。

  • CardTable:ART虚拟机中,CardTable可看作是一个元素大小为1字节的数组,该数组的每一个元素叫作一个Card(大小为1字节,不同虚拟机有不同的取值)。
    然后对AllocatedSpace按128字节(不同虚拟机有不同的取值)大小进行划分。每一个Card对应为Space中的一个128字节区域。
    所以,凡是内存地址位于某一个128字节区域的Object对象都对应同一个Card。
    在这个128字节区域内的Object对象中,只要有一个引用了新生代的对象,则该区域对应的Card元素将被标记为脏Card(Dirty Card)。

  • 简单来说,RememberedSet是以单个Object为管理对象,而CardTable是以128字节空间为管理对象。这128字节的空间中可能存在多个Object。

  • The mod-union table is the union of modified cards. It is used to allow the card table to be cleared between GC phases, reducing the number of dirty cards that need to be scanned.

  • ModUnionTable是Union of Modified Cards的意思,用于减少GC的工作量。

  • ModUnionTable只和ImageSpace、ZygoteSpace相关联。而RememberedSet只和MallocSpace(DlMallocSpace或RosAllocSpace)关联。

  • 在ART虚拟机中,RememberedSet和ModUnionTable都和GC密切相关。本质上来说,它们内部操作的都是CardTable。

关系

下图展示了ART虚拟机中CardTable、Space、RememberedSet和ModUnionTable之间的关系。
image.png

  • CardTable,它是一个数组,元素大小为1字节。该数组构造在一个内存映射对象上,起始位置为4KB,结尾为4GB。注意,CardTable前面一段灰色区域用于对齐。Heap利用这一个CardTable对象维护了Heap中其他空间所需的card信息。
  • 上方为一个ContinuousSpace对象(严格来说是一个MallocSpace对象)。它们按kCardSize(128字节)进行划分。每一个kCardSize单元可映射到CardTable中的一个Card。
  • 一个RememberedSet会关联一个ContinuousSpace,它用于记录该ContinuousSpace空间中的Object是否引用了其他Space空间中的Object等信息。
    也就是说,我们要想了解或操作某个ContinuousSpace和其他Space空间中Object引用关系的话,只要通过这个ContinuousSpace所关联的RememberedSet即可,而无须操作整个CardTable。
    另外,代码中只有DlMallocSpace或RosAllocSpace会关联RememberedSet。Bump-PointerSpace和RegionSpace均没有使用它。
  • 下方为一个ImageSpace或ZygoteSpace对象,它会关联一个ModUnionTable对象。在代码中,只有ImageSpace或ZygoteSpace这两种类型的Space对象会使用ModUnion-Table。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baiiu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值