## 码字不易,请大佬们点点关注,谢谢~
一、Android Runtime堆内存架构概述
Android Runtime(ART)的堆内存架构是保障应用程序对象存储与管理的核心组件,其设计直接影响到内存分配效率、垃圾回收性能以及应用的稳定性。ART堆内存架构在源码中主要分布于art/runtime/gc/
目录下,涵盖内存分配策略、垃圾回收算法、内存碎片化处理等多个关键模块。理解其设计原理,对于优化应用内存使用、减少内存泄漏风险以及提升系统整体性能具有重要意义。
二、堆内存架构的基础组件与数据结构
2.1 核心组件构成
ART堆内存架构由多个核心组件协同工作:
- 内存分配器(Memory Allocator) :位于
art/runtime/gc/allocator/
目录,负责处理对象的内存分配请求。其核心类Allocator
在art/runtime/gc/allocator/allocator.cc
中实现,提供不同类型的分配策略,如快速分配、按需分配等。
cpp
// Allocator类为对象分配内存
class Allocator {
public:
// 尝试分配指定大小的内存块
void* Allocate(size_t size) {
// 检查是否存在可用的空闲内存块
FreeList* free_list = GetFreeListForSize(size);
if (free_list != nullptr && free_list->HasFreeBlock(size)) {
// 从空闲链表中获取内存块
return free_list->AllocateBlock(size);
}
// 若空闲链表中无合适内存块,则请求堆扩展
return Heap::Current()->RequestHeapGrowth(size);
}
private:
// 根据内存大小获取对应的空闲链表
FreeList* GetFreeListForSize(size_t size) {
// 计算内存块所属的大小类别
size_t class_index = SizeClassForSize(size);
// 返回对应类别的空闲链表
return free_lists_[class_index];
}
// 存储不同大小类别的空闲链表
FreeList* free_lists_[kNumSizeClasses];
};
- 垃圾回收器(Garbage Collector) :在
art/runtime/gc/gc.cc
中定义,负责识别并回收不再使用的对象内存。ART支持多种垃圾回收算法,如标记-清除(Mark-Sweep)、标记-压缩(Mark-Compact)等,通过GcType
枚举区分不同算法类型。
cpp
// GcType枚举定义不同的垃圾回收类型
enum class GcType {
kMarkSweep, // 标记-清除算法
kMarkCompact, // 标记-压缩算法
kCopying, // 复制算法
};
// GC类负责执行垃圾回收操作
class GC {
public:
void Collect(GcType type) {
if (type == GcType::kMarkSweep) {
MarkSweepCollector().Collect();
} else if (type == GcType::kMarkCompact) {
MarkCompactCollector().Collect();
} else if (type == GcType::kCopying) {
CopyingCollector().Collect();
}
}
};
- 内存映射管理器(Memory Mapping Manager) :在
art/runtime/memory/memory_mapping.cc
中实现,负责管理堆内存与物理内存的映射关系,处理内存的分配、释放和保护属性设置。
2.2 关键数据结构
ART堆内存使用多种数据结构管理内存状态:
- 空闲链表(Free List) :用于存储空闲内存块,每个链表对应一种特定大小范围的内存块。在
art/runtime/gc/allocator/free_list.cc
中定义:
cpp
// FreeList类表示空闲内存块链表
class FreeList {
public:
FreeList() : head_(nullptr) {}
// 检查链表中是否存在大小满足要求的空闲块
bool HasFreeBlock(size_t size) {
FreeBlock* current = head_;
while (current != nullptr) {
if (current->size_ >= size) {
return true;
}
current = current->next_;
}
return false;
}
// 从链表中分配一个大小满足要求的内存块
void* AllocateBlock(size_t size) {
FreeBlock* current = head_;
FreeBlock* prev = nullptr;
while (current != nullptr && current->size_ < size) {
prev = current;
current = current->next_;
}
if (current == nullptr) {
return nullptr;
}
if (prev == nullptr) {
head_ = current->next_;
} else {
prev->next_ = current->next_;
}
return current->data_;
}
private:
// 空闲内存块结构体
struct FreeBlock {
void* data_; // 内存块起始地址
size_t size_; // 内存块大小
FreeBlock* next_; // 指向下一个空闲块的指针
};
FreeBlock* head_; // 链表头指针
};
- 对象头(Object Header) :每个对象在堆内存中都包含对象头,存储对象的元数据信息,如对象大小、哈希码、分代信息等。在
art/runtime/mirror/object_header.h
中定义:
cpp
// ObjectHeader结构体表示对象头
struct ObjectHeader {
uint32_t size_; // 对象大小(包括对象头)
uint32_t hash_code_; // 对象哈希码
uint8_t age_; // 对象分代年龄
uint8_t lock_word_; // 对象锁信息
};
这些数据结构为内存的高效管理和操作提供了基础支持。
三、堆内存的初始化与布局
3.1 堆内存初始化流程
ART堆内存的初始化在系统启动或应用进程创建时完成,主要逻辑位于art/runtime/gc/heap.cc
中:
cpp
// Heap类表示ART堆内存
class Heap {
public:
static Heap* Current() {
// 返回当前线程对应的堆实例
return Thread::Current()->GetHeap();
}
bool Initialize() {
// 分配堆内存的基础区域
if (!AllocateBaseMemory()) {
return false;
}
// 初始化空闲链表
InitializeFreeLists();
// 初始化垃圾回收器
if (!gc_.Initialize()) {
return false;
}
return true;
}
private:
// 分配堆内存的基础区域
bool AllocateBaseMemory() {
// 计算初始堆内存大小
size_t initial_size = CalculateInitialHeapSize();
// 通过系统调用分配内存
void* base_memory = os::Memory::Map(nullptr, initial_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (base_memory == MAP_FAILED) {
return false;
}
base_address_ = reinterpret_cast<uint8_t*>(base_memory);
end_address_ = base_address_ + initial_size;
return true;
}
// 初始化空闲链表
void InitializeFreeLists() {
for (size_t i = 0; i < kNumSizeClasses; ++i) {
free_lists_[i] = new FreeList();
}
// 将初始堆内存划分为空闲块并加入链表
FreeList* large_list = free_lists_[kLargeSizeClassIndex];
large_list->InsertBlock(base_address_, end_address_ - base_address_);
}
uint8_t* base_address_; // 堆内存起始地址
uint8_t* end_address_; // 堆内存结束地址
FreeList* free_lists_[kNumSizeClasses]; // 空闲链表数组
GC gc_; // 垃圾回收器实例
};
初始化过程包括内存分配、空闲链表设置和垃圾回收器配置,为后续的内存使用做好准备。
3.2 堆内存布局设计
ART堆内存采用分代(Generational)布局,将内存划分为不同代,以优化垃圾回收效率。主要分为以下几个区域:
- 新生代(Young Generation) :存储新创建的对象,分为Eden空间和两个Survivor空间(From Space和To Space)。在
art/runtime/gc/heap.h
中定义:
cpp
class Heap {
private:
uint8_t* eden_start_; // Eden空间起始地址
uint8_t* eden_end_; // Eden空间结束地址
uint8_t* from_space_start_; // From Space起始地址
uint8_t* from_space_end_; // From Space结束地址
uint8_t* to_space_start_; // To Space起始地址
uint8_t* to_space_end_; // To Space结束地址
};
- 老年代(Old Generation):存储在新生代中经过多次垃圾回收后存活下来的对象。
- 永久代(Permanent Generation,在Java 8后被元空间取代):存储类元数据、方法数据等。
这种布局方式基于大部分对象生命周期较短的特点,通过分代回收减少垃圾回收的扫描范围,提升回收效率。
四、对象内存分配策略
4.1 快速分配路径
对于小对象和频繁分配的场景,ART采用快速分配路径以提高效率。在art/runtime/gc/allocator/allocator.cc
中:
cpp
class Allocator {
public:
void* AllocateFast(size_t size) {
// 检查线程本地分配缓冲区(TLAB)是否有足够空间
Thread* self = Thread::Current();
Tlab* tlab = self->GetTlab();
if (tlab->HasRoomFor(size)) {
// 从TLAB中直接分配内存
return tlab->Allocate(size);
}
// TLAB空间不足,尝试重新填充或分配新的TLAB
if (!tlab->Refill()) {
// 重新分配TLAB
tlab->AllocateTlab();
}
return tlab->Allocate(size);
}
};
线程本地分配缓冲区(TLAB)为每个线程提供专属的内存分配区域,减少多线程环境下的锁竞争,加快分配速度。
4.2 按需分配与堆扩展
当快速分配路径无法满足需求时,会进入按需分配流程,并可能触发堆内存扩展:
cpp
class Allocator {
public:
void* Allocate(size_t size) {
if (size <= kMaxTlabAllocationSize) {
return AllocateFast(size);
}
// 对于大对象或TLAB无法满足的对象,直接请求堆扩展
return Heap::Current()->RequestHeapGrowth(size);
}
};
class Heap {
public:
void* RequestHeapGrowth(size_t size) {
// 计算需要扩展的内存大小
size_t required_size = CalculateRequiredGrowthSize(size);
// 通过系统调用扩展堆内存
void* new_memory = os::Memory::Map(nullptr, required_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (new_memory == MAP_FAILED) {
return nullptr;
}
// 将新分配的内存加入堆管理
AddMemoryRegion(reinterpret_cast<uint8_t*>(new_memory), required_size);
// 在新内存中分配对象
return AllocateFromNewRegion(size);
}
};
按需分配策略确保即使在内存紧张的情况下,也能为对象分配足够的内存空间。
五、垃圾回收算法与执行流程
5.1 标记-清除算法实现
标记-清除算法是ART中常用的垃圾回收算法之一,其核心逻辑在art/runtime/gc/collector/mark_sweep_collector.cc
中:
cpp
// MarkSweepCollector类实现标记-清除算法
class MarkSweepCollector {
public:
void Collect() {
// 暂停所有应用线程(Stop The World)
Thread::SuspendAll();
// 标记所有可达对象
MarkReachableObjects();
// 清除所有未标记的对象(回收空闲内存)
SweepUnmarkedObjects();
// 恢复应用线程
Thread::ResumeAll();
}
private:
// 从根集合(如栈、静态变量)开始标记可达对象
void MarkReachableObjects() {
RootVisitor root_visitor;
root_visitor.VisitRoots();
}
// 扫描堆内存,回收未标记的对象
void SweepUnmarkedObjects() {
uint8_t* current = Heap::Current()->GetHeapStart();
uint8_t* end = Heap::Current()->GetHeapEnd();
while (current < end) {
ObjectHeader* header = reinterpret_cast<ObjectHeader*>(current);
if (!header->IsMarked()) {
// 对象未标记,回收内存
FreeBlock(block);
} else {
// 对象已标记,清除标记位为下次回收做准备
header->ClearMark();
}
current += header->size_;
}
}
};
标记-清除算法通过两轮扫描完成垃圾回收,但可能导致内存碎片化问题。
5.2 标记-压缩算法实现
为解决内存碎片化问题,ART引入标记-压缩算法,在art/runtime/gc/collector/mark_compact_collector.cc
中实现:
cpp
// MarkCompactCollector类实现标记-压缩算法
class MarkCompactCollector {
public:
void Collect() {
Thread::SuspendAll();
// 标记可达对象
MarkReachableObjects();
// 计算对象新的地址(压缩阶段)
CalculateNewObjectAddresses();
// 移动可达对象到新地址
CompactObjects();
// 清除空闲内存
SweepFreeMemory();
Thread::ResumeAll();
}
private:
// 计算对象在压缩后的新地址
void CalculateNewObjectAddresses() {
uint8_t* new_start = Heap::Current()->GetHeapStart();
uint8_t* current = Heap::Current()->GetHeapStart();
uint8_t* end = Heap::Current()->GetHeapEnd();
while (current < end) {
ObjectHeader* header = reinterpret_cast<ObjectHeader*>(current);
if (header->IsMarked()) {
header->SetNewAddress(new_start);
new_start += header->size_;
}
current += header->size_;
}
}
// 将可达对象移动到新地址
void CompactObjects() {
uint8_t* current = Heap::Current()->GetHeapStart();
uint8_t* end = Heap::Current()->GetHeapEnd();
while (current < end) {
ObjectHeader* header = reinterpret_cast<ObjectHeader*>(current);
if (header->IsMarked()) {
void* new_address = header->GetNewAddress();
memmove(new_address, current, header->size_);
}
current += header->size_;
}
}
};
标记-压缩算法在回收垃圾的同时,通过移动对象压缩内存空间,减少碎片化,提高内存利用率。
六、内存碎片化处理机制
6.1 空闲内存合并
ART通过空闲内存合并减少碎片化,在对象释放时检查相邻内存块是否空闲,若空闲则合并。在art/runtime/gc/allocator/free_list.cc
中:
cpp
class FreeList {
public:
void FreeBlock(void* block) {
FreeBlock* free_block = reinterpret_cast<FreeBlock*>(block - offsetof(FreeBlock, data_));
// 检查前一个内存块是否空闲
FreeBlock* prev = FindPreviousFreeBlock(free_block);
if (prev != nullptr && IsAdjacent(prev, free_block)) {
prev->size_ += free_block->size_;
free_block = prev;
}
// 检查后一个内存块是否空闲
FreeBlock* next = free_block->next_;
if (next != nullptr && IsAdjacent(free_block, next)) {
free_block->size_ += next->size_;
free_block->next_ = next->next_;
}
// 将合并后的内存块插入空闲链表
InsertBlock(free_block->data_, free_block->size_);
}
private:
// 判断两个内存块是否相邻
bool IsAdjacent(FreeBlock* block1, FreeBlock* block2) {
return reinterpret_cast<uint8_t*>(block1->data_) + block1->size_ == reinterpret_cast<uint8_t*>(block2->data_);
}
};
通过合并相邻空闲块,扩大空闲内存块的大小,提高大块内存分配的成功率。
6.2 内存整理策略
除了垃圾回收时的标记-压缩,ART还会在特定情况下触发内存整理,进一步减少碎片化。在art/runtime/gc/heap.cc
中:
cpp
class Heap {
public:
void Defragment() {
// 判断是否需要进行内存整理(如碎片化程度超过阈值)
if (IsFragmentationLevelHigh()) {
// 执行标记-压缩垃圾回收
GC::Current()->Collect(GcType::kMarkCompact);
}
}
private:
// 判断内存碎片化程度是否过高
bool
Android Runtime堆内存架构设计深度剖析(续)
六、内存碎片化处理机制(续)
6.2 内存整理策略(续)
cpp
bool IsFragmentationLevelHigh() {
// 计算空闲内存块的平均大小与总堆内存的比例
size_t total_free_size = 0;
size_t num_free_blocks = 0;
for (size_t i = 0; i < kNumSizeClasses; ++i) {
FreeList* free_list = free_lists_[i];
FreeBlock* current = free_list->GetHead();
while (current != nullptr) {
total_free_size += current->size_;
num_free_blocks++;
current = current->next_;
}
}
size_t average_free_size = (num_free_blocks > 0) ? total_free_size / num_free_blocks : 0;
size_t heap_size = end_address_ - base_address_;
// 设定阈值,当平均空闲大小低于阈值时认为碎片化严重
return average_free_size < kFragmentationThreshold * heap_size;
}
};
通过定期评估碎片化程度并执行标记 - 压缩回收,ART能有效缓解内存碎片化问题,保障后续内存分配的高效性。
6.3 伙伴系统(Buddy System)的应用
在处理大块内存分配与回收时,ART引入伙伴系统算法优化管理。伙伴系统将内存块按2的幂次方大小进行划分和合并,在art/runtime/gc/allocator/buddy_allocator.cc
中实现:
cpp
// BuddyAllocator类实现伙伴系统
class BuddyAllocator {
public:
BuddyAllocator() {
// 初始化不同大小级别的空闲内存块链表
for (int i = 0; i < kMaxBuddyLevels; ++i) {
free_lists_[i] = nullptr;
}
}
void* Allocate(size_t size) {
int level = CalculateBuddyLevel(size);
for (int i = level; i < kMaxBuddyLevels; ++i) {
if (free_lists_[i] != nullptr) {
// 找到合适大小的空闲块
BuddyBlock* block = free_lists_[i];
RemoveFromList(block, i);
if (i > level) {
// 分割大块内存为两个伙伴块
SplitBlock(block, i);
// 递归分配更小的块
return Allocate(size);
}
return block->data;
}
}
// 无合适空闲块,请求堆扩展
return nullptr;
}
void Free(void* block) {
BuddyBlock* buddy_block = reinterpret_cast<BuddyBlock*>(block - offsetof(BuddyBlock, data));
int level = buddy_block->level;
// 尝试与伙伴块合并
BuddyBlock* buddy = GetBuddy(buddy_block);
if (buddy != nullptr && buddy->IsFree()) {
MergeBlocks(buddy_block, buddy);
Free(buddy_block);
return;
}
// 无法合并,将块加入对应链表
AddToList(buddy_block, level);
}
private:
struct BuddyBlock {
void* data;
int level; // 块大小级别
BuddyBlock* next;
BuddyBlock* prev;
bool is_free;
};
BuddyBlock* free_lists_[kMaxBuddyLevels];
int CalculateBuddyLevel(size_t size) {
// 计算满足大小需求的最小2的幂次方级别
int level = 0;
size_t block_size = 1;
while (block_size < size) {
block_size <<= 1;
level++;
}
return level;
}
BuddyBlock* GetBuddy(BuddyBlock* block) {
// 根据块地址和级别计算伙伴块地址
uintptr_t buddy_address = reinterpret_cast<uintptr_t>(block->data) ^ (1 << block->level);
return reinterpret_cast<BuddyBlock*>(buddy_address - offsetof(BuddyBlock, data));
}
void SplitBlock(BuddyBlock* block, int level) {
// 将大块内存分割为两个伙伴块
size_t block_size = 1 << level;
BuddyBlock* new_block = reinterpret_cast<BuddyBlock*>(reinterpret_cast<uint8_t*>(block->data) + block_size);
new_block->level = level - 1;
new_block->is_free = true;
// 调整链表关系
}
void MergeBlocks(BuddyBlock* block1, BuddyBlock* block2) {
// 合并两个伙伴块
BuddyBlock* larger_block = (reinterpret_cast<uintptr_t>(block1) < reinterpret_cast<uintptr_t>(block2)) ? block1 : block2;
larger_block->level++;
// 从链表中移除较小块并更新指针
}
void AddToList(BuddyBlock* block, int level) {
// 将块加入对应级别的空闲链表
}
void RemoveFromList(BuddyBlock* block, int level) {
// 从链表中移除块
}
static const int kMaxBuddyLevels = 16;
};
伙伴系统通过高效的分割与合并策略,减少大块内存分配时的碎片化问题,提升内存使用效率。
七、多线程环境下的内存管理
7.1 线程本地分配缓冲区(TLAB)
TLAB是ART应对多线程内存分配的核心机制,每个线程拥有专属的TLAB区域,减少锁竞争。在art/runtime/gc/allocator/tlab.cc
中:
cpp
// Tlab类表示线程本地分配缓冲区
class Tlab {
public:
Tlab() : start_(nullptr), top_(nullptr), end_(nullptr) {}
bool Initialize(size_t size) {
// 从堆中分配TLAB内存
start_ = reinterpret_cast<uint8_t*>(Heap::Current()->Allocate(size));
if (start_ == nullptr) {
return false;
}
top_ = start_;
end_ = start_ + size;
return true;
}
void* Allocate(size_t size) {
// 检查TLAB剩余空间是否足够
if (top_ + size > end_) {
return nullptr;
}
void* result = top_;
top_ += size;
return result;
}
bool HasRoomFor(size_t size) {
return top_ + size <= end_;
}
bool Refill() {
// 尝试从堆中补充TLAB空间
size_t remaining = end_ - top_;
size_t needed = kTlabRefillSize - remaining;
void* new_memory = Heap::Current()->Allocate(needed);
if (new_memory == nullptr) {
return false;
}
// 复制剩余数据并更新指针
memmove(start_, top_, remaining);
top_ = start_ + remaining;
end_ = start_ + kTlabRefillSize;
return true;
}
private:
uint8_t* start_; // TLAB起始地址
uint8_t* top_; // 当前分配指针
uint8_t* end_; // TLAB结束地址
static const size_t kTlabRefillSize = 64 * 1024; // TLAB补充大小
};
TLAB使得多数小对象分配可在无锁状态下完成,显著提升多线程场景下的内存分配性能。
7.2 锁机制与同步策略
对于无法在TLAB中完成的分配或涉及全局堆操作时,ART使用锁机制确保线程安全。在art/runtime/gc/heap.cc
中:
cpp
class Heap {
public:
void* AllocateLargeObject(size_t size) {
std::lock_guard<Mutex> lock(heap_mutex_);
// 分配大块内存,可能触发堆扩展
return RequestHeapGrowth(size);
}
private:
Mutex heap_mutex_; // 堆操作互斥锁
};
通过互斥锁heap_mutex_
,ART保证同一时刻只有一个线程能进行影响全局堆状态的操作,如堆扩展、全局垃圾回收触发等,避免数据竞争与不一致问题。
7.3 并发垃圾回收(Concurrent GC)
为减少垃圾回收对应用线程的暂停时间,ART支持并发垃圾回收。在art/runtime/gc/collector/concurrent_collector.cc
中:
cpp
// ConcurrentCollector类实现并发垃圾回收
class ConcurrentCollector {
public:
void Collect() {
// 初始标记阶段:暂停所有线程标记根对象
Thread::SuspendAll();
MarkRoots();
Thread::ResumeAll();
// 并发标记阶段:与应用线程同时运行,标记可达对象
ConcurrentMark();
// 重新标记阶段:短暂暂停线程处理并发期间的引用变化
Thread::SuspendAll();
Remark();
Thread::ResumeAll();
// 并发清除阶段:与应用线程同时回收垃圾
ConcurrentSweep();
}
private:
void ConcurrentMark() {
// 从根对象开始,并发遍历对象图标记可达对象
// 使用写屏障(Write Barrier)处理对象引用变化
}
void Remark() {
// 扫描栈、寄存器等重新标记漏标的可达对象
}
void ConcurrentSweep() {
// 遍历堆内存,回收未标记的垃圾对象
}
};
并发垃圾回收通过分阶段执行,在保证回收正确性的前提下,最大限度减少对应用线程的阻塞,提升用户体验。
八、堆内存与其他系统组件的交互
8.1 与虚拟内存管理的协作
ART堆内存依赖操作系统的虚拟内存管理机制完成物理内存映射。在art/runtime/memory/memory_mapping.cc
中:
cpp
// MemoryMapping类管理内存映射
class MemoryMapping {
public:
static void* MapMemory(size_t size, int prot, int flags, int fd, off_t offset) {
// 调用系统内存映射函数mmap
void* result = mmap(nullptr, size, prot, flags, fd, offset);
if (result == MAP_FAILED) {
PLOG(ERROR) << "Failed to map memory";
return nullptr;
}
return result;
}
static int UnmapMemory(void* addr, size_t size) {
// 调用系统内存解除映射函数munmap
int result = munmap(addr, size);
if (result == -1) {
PLOG(ERROR) << "Failed to unmap memory";
}
return result;
}
};
通过mmap
和munmap
系统调用,ART实现堆内存的动态扩展与释放,并利用虚拟内存的分页机制提升内存访问效率。
8.2 与Java虚拟机(JVM)接口的集成
ART堆内存架构需与Java虚拟机的对象模型紧密配合。在art/runtime/mirror/object.cc
中:
cpp
// Object类表示Java对象在ART中的镜像
class Object {
public:
static size_t GetObjectSize(const Object* obj) {
// 获取对象头中的大小信息
return obj->GetObjectHeader()->size_;
}
static void* GetObjectData(const Object* obj) {
// 返回对象数据部分的起始地址
return reinterpret_cast<void*>(obj + 1);
}
ObjectHeader* GetObjectHeader() const {
return reinterpret_cast<ObjectHeader*>(this);
}
};
这些接口为JVM提供对象内存布局信息,支持对象访问、字段操作以及多态方法调用等核心功能。
8.3 与性能分析工具的交互
ART堆内存架构为性能分析工具提供数据接口,如内存分配统计、垃圾回收日志记录等。在art/runtime/gc/heap_profiler.cc
中:
cpp
// HeapProfiler类用于堆内存性能分析
class HeapProfiler {
public:
void StartRecording() {
// 开始记录内存分配、释放事件
recording_ = true;
// 初始化统计数据结构
}
void RecordAllocation(void* object, size_t size) {
if (recording_) {
// 记录对象分配时间、大小及所属线程
allocation_log_.push_back({std::chrono::high_resolution_clock::now(), object, size, Thread::Current()});
}
}
void RecordFree(void* object) {
if (recording_) {
// 记录对象释放事件
}
}
const std::vector<AllocationRecord>& GetAllocationLog() const {
return allocation_log_;
}
private:
bool recording_;
std::vector<AllocationRecord> allocation_log_;
struct AllocationRecord {
std::chrono::high_resolution_clock::time_point time;
void* object;
size_t size;
Thread* thread;
};
};
通过这些记录,开发者可利用adb shell dumpsys meminfo
等工具分析内存使用情况,定位内存泄漏与性能瓶颈。
九、堆内存架构的性能优化策略
9.1 减少内存分配开销
ART通过多种策略降低内存分配开销:
- 预分配策略 :在应用启动或特定场景下,预先分配一定量的内存,减少后续实时分配次数。在
art/runtime/gc/heap.cc
中:
cpp
class Heap {
public:
void PreAllocateMemory(size_t size) {
// 提前请求堆扩展
RequestHeapGrowth(size);
// 将预分配内存加入空闲链表
FreeList* large_list = free_lists_[kLargeSizeClassIndex];
large_list->InsertBlock(end_address_ - size, size);
}
};
- 对象池复用 :对于频繁创建和销毁的对象(如线程池中的任务对象),使用对象池机制复用对象,避免重复分配与回收。在
art/runtime/object_pool.cc
中:
cpp
// ObjectPool类实现对象池
template <typename T>
class ObjectPool {
public:
ObjectPool(size_t initial_size) {
// 初始化对象池,创建初始数量的对象
for (size_t i = 0; i < initial_size; ++i) {
objects_.push(new T());
}
}
T* Acquire() {
if (objects_.empty()) {
// 对象池为空时创建新对象
return new T();
}
T* object = objects_.top();
objects_.pop();
return object;
}
void Release(T* object) {
// 将对象放回对象池
objects_.push(object);
}
private:
std::stack<T*> objects_;
};
9.2 优化垃圾回收性能
ART通过算法改进与参数调优提升垃圾回收效率:
- 分代回收优化 :根据对象存活周期调整回收频率,新生代采用复制算法快速回收短命对象,老年代使用标记 - 压缩算法处理长生命周期对象。在
art/runtime/gc/gc_policy.cc
中:
cpp
// GcPolicy类制定垃圾回收策略
class GcPolicy {
public:
GcType SelectGcType(Object* object) {
if (object->GetObjectHeader()->age_ < kYoungGenerationThreshold) {
return GcType::kCopying;
}
return GcType::kMarkCompact;
}
private:
static const int kYoungGenerationThreshold = 3; // 对象晋升老年代的年龄阈值
};
- 自适应回收参数调整 :根据应用内存使用情况动态调整垃圾回收阈值与频率。在
art/runtime/gc/gc_controller.cc
中:
cpp
// GcController类控制垃圾回收时机
class GcController {
public:
void AdjustGcParameters() {
size_t used_memory = CalculateUsedMemory();
size_t total_memory = Heap::Current()->GetHeapSize();
if (used_memory / static_cast<double>(total_memory) > kHighUsageThreshold) {
// 内存使用率过高,降低触发回收的阈值
SetGcTriggerThreshold(kLowerThreshold);
} else if (used_memory / static_cast<double>(total_memory) < kLowUsageThreshold) {
// 内存使用率较低,提高触发回收的阈值
SetGcTriggerThreshold(kHigherThreshold);
}
}
private:
static const double kHighUsageThreshold = 0.8;
static const double kLowUsageThreshold = 0.4;
void SetGcTriggerThreshold(size_t threshold) {
// 更新垃圾回收触发阈值
}
};
9.3 内存压缩与紧凑
除标记 - 压缩垃圾回收外,ART还在后台执行定期内存整理任务。在art/runtime/gc/background_compaction.cc
中:
cpp
// BackgroundCompactionTask类执行后台内存整理
class BackgroundCompactionTask : public Task {
public:
void Run() override {
while (true) {
std::this_thread::sleep_for(std::chrono::minutes(5)); // 每5分钟执行一次
if (Heap::Current()->IsFragmentationLevelHigh()) {
GC::Current()->Collect(GcType::kMarkCompact);
}
}
}
};
Android Runtime堆内存架构设计深度剖析(续)
十、堆内存架构的安全与稳定性保障
10.1 内存越界与非法访问防护
为防止对象访问时出现内存越界和非法访问,ART在对象头和内存分配边界设置多重校验机制。在art/runtime/mirror/object_header.h
中,对象头包含对象大小信息,用于在访问对象字段或数组元素时进行边界检查:
cpp
// ObjectHeader结构体表示对象头
struct ObjectHeader {
uint32_t size_; // 对象大小(包括对象头)
// 其他元数据...
// 检查目标偏移是否在对象边界内
bool IsOffsetInBounds(size_t offset) const {
return offset < size_;
}
};
// 在访问对象字段时的边界检查示例
template<typename T>
T Object::GetField(size_t offset) const {
ObjectHeader* header = GetObjectHeader();
if (!header->IsOffsetInBounds(offset + sizeof(T))) {
LOG(FATAL) << "Field access out of bounds";
}
return *reinterpret_cast<const T*>(reinterpret_cast<const uint8_t*>(this) + offset);
}
此外,在内存分配和释放阶段,Allocator
类通过空闲链表管理和内存块边界标记,避免释放已分配内存或重复释放同一内存块:
cpp
class FreeList {
private:
// 插入内存块到链表时,记录块的边界信息
void InsertBlock(void* block, size_t size) {
FreeBlock* new_block = new FreeBlock();
new_block->data_ = block;
new_block->size_ = size;
new_block->next_ = head_;
if (head_ != nullptr) {
head_->prev_ = new_block;
}
head_ = new_block;
}
// 释放内存块时,验证块的有效性
bool IsValidBlock(void* block) {
FreeBlock* current = head_;
while (current != nullptr) {
if (current->data_ == block) {
return true;
}
current = current->next_;
}
return false;
}
};
10.2 内存泄漏检测与预防
ART通过垃圾回收机制自动释放不再使用的对象,但对于存在循环引用等特殊场景导致的潜在内存泄漏,提供辅助检测工具。在art/runtime/gc/leak_detector.cc
中实现了简单的内存泄漏检测逻辑:
cpp
class LeakDetector {
public:
LeakDetector() {
// 初始化时记录所有已分配对象
Heap* heap = Heap::Current();
uint8_t* current = heap->GetHeapStart();
uint8_t* end = heap->GetHeapEnd();
while (current < end) {
ObjectHeader* header = reinterpret_cast<ObjectHeader*>(current);
allocated_objects_.insert(reinterpret_cast<void*>(header));
current += header->size_;
}
}
// 检测是否存在未被回收的对象
bool CheckForLeaks() {
Heap* heap = Heap::Current();
uint8_t* current = heap->GetHeapStart();
uint8_t* end = heap->GetHeapEnd();
std::unordered_set<void*> live_objects;
// 标记所有可达对象
GC::Current()->MarkReachableObjects(live_objects);
std::unordered_set<void*> leaked_objects;
for (void* obj : allocated_objects_) {
if (live_objects.find(obj) == live_objects.end()) {
leaked_objects.insert(obj);
}
}
return !leaked_objects.empty();
}
private:
std::unordered_set<void*> allocated_objects_;
};
同时,ART还通过弱引用(WeakReference)和软引用(SoftReference)机制,允许开发者手动管理对象生命周期,避免因强引用导致的内存泄漏:
cpp
// 弱引用示例
class WeakReferenceObject {
public:
WeakReferenceObject(Object* target) : weak_ref_(target) {}
Object* Get() {
return weak_ref_.Get();
}
private:
WeakReference<mirror::Object> weak_ref_;
};
10.3 内存压力应对策略
当系统内存不足时,ART通过一系列策略保障应用稳定性。首先,在art/runtime/gc/gc_limits.cc
中定义了内存使用的阈值和限制:
cpp
class GcLimits {
public:
GcLimits() {
// 设置堆内存使用的软限制和硬限制
soft_limit_ = GetSystemMemory() * 0.6; // 软限制为系统内存的60%
hard_limit_ = GetSystemMemory() * 0.8; // 硬限制为系统内存的80%
}
bool IsAboveSoftLimit(size_t used_memory) const {
return used_memory > soft_limit_;
}
bool IsAboveHardLimit(size_t used_memory) const {
return used_memory > hard_limit_;
}
private:
size_t soft_limit_;
size_t hard_limit_;
size_t GetSystemMemory() const {
// 通过系统接口获取总内存大小
}
};
当内存使用超过软限制时,ART会主动触发更频繁的垃圾回收;若达到硬限制,则会终止部分后台进程或抛出OutOfMemoryError
异常。此外,ART还支持内存压缩(Memory Compression)技术,在art/runtime/memory/memory_compression.cc
中实现:
cpp
class MemoryCompressor {
public:
bool CompressMemory() {
// 检查是否满足压缩条件(如内存使用率过高)
if (IsMemoryPressureHigh()) {
// 对部分冷数据进行压缩
CompressColdData();
return true;
}
return false;
}
private:
bool IsMemoryPressureHigh() const {
// 检查内存使用情况和系统负载
}
void CompressColdData() {
// 扫描堆内存,识别长时间未访问的对象并压缩
}
};
通过内存压缩,在不释放内存的情况下减少物理内存占用,缓解系统内存压力。
十一、堆内存架构的演进与未来趋势
11.1 从传统堆到ZGC的技术突破
随着Android系统的发展,ART堆内存架构逐渐引入更先进的垃圾回收算法。以ZGC(Z Garbage Collector)为例,其在art/runtime/gc/collector/zgc/
目录下实现,通过染色指针(Colored Pointers)和读屏障(Read Barrier)技术,实现几乎无停顿的垃圾回收:
cpp
// ZgcCollector类实现ZGC核心逻辑
class ZgcCollector {
public:
void Collect() {
// 并发标记阶段:使用染色指针标记可达对象
ConcurrentMark();
// 并发转移阶段:将存活对象转移到新区域
ConcurrentRelocate();
// 并发重映射阶段:更新对象引用
ConcurrentRemap();
}
private:
void ConcurrentMark() {
// 利用读屏障记录对象引用变化
SetReadBarrier(true);
// 从根集合开始并发标记
MarkRoots();
TraverseObjectGraph();
SetReadBarrier(false);
}
void ConcurrentRelocate() {
// 并发扫描堆内存,将存活对象复制到新区域
ScanHeapAndRelocate();
}
void ConcurrentRemap() {
// 更新所有指向已转移对象的引用
UpdateReferences();
}
};
ZGC的引入大幅提升了大内存场景下的垃圾回收性能,减少应用卡顿现象。
11.2 面向异构内存的架构优化
随着Android设备集成多种内存类型(如DRAM、NVM),未来ART堆内存架构需支持异构内存管理。在art/runtime/gc/heterogeneous_memory_manager.cc
中可展望其实现方向:
cpp
class HeterogeneousMemoryManager {
public:
HeterogeneousMemoryManager() {
// 初始化不同类型内存的管理模块
dram_allocator_ = new DramAllocator();
nvm_allocator_ = new NvmAllocator();
}
void* Allocate(size_t size, MemoryType type) {
if (type == kDram) {
return dram_allocator_->Allocate(size);
} else if (type == kNvm) {
return nvm_allocator_->Allocate(size);
}
return nullptr;
}
void Free(void* block, MemoryType type) {
if (type == kDram) {
dram_allocator_->Free(block);
} else if (type == kNvm) {
nvm_allocator_->Free(block);
}
}
private:
DramAllocator* dram_allocator_;
NvmAllocator* nvm_allocator_;
};
通过区分不同内存类型的特性(如读写速度、持久性),ART可将热数据存储在DRAM中保证访问效率,冷数据存储在NVM中降低功耗,实现内存资源的最优分配。
11.3 人工智能驱动的内存管理
未来ART堆内存架构可能引入机器学习技术,实现智能内存管理。在art/runtime/gc/ml_memory_manager.cc
中可设想其实现框架:
cpp
class MlMemoryManager {
public:
MlMemoryManager() {
// 加载预训练的内存管理模型
std::unique_ptr<tflite::FlatBufferModel> model =
tflite::FlatBufferModel::BuildFromFile("memory_management_model.tflite");
tflite::InterpreterBuilder(*model, resolver_)(&interpreter_);
interpreter_->AllocateTensors();
}
void* Allocate(size_t size) {
// 提取内存分配请求的特征(如大小、频率、线程信息)
std::vector<float> features = ExtractAllocationFeatures(size);
// 使用模型预测最佳分配策略
SetInputTensorData(features);
interpreter_->Invoke();
std::vector<float> output = GetOutputTensorData();
int strategy_index = static_cast<int>(output[0]);
if (strategy_index == 0) {
return AllocateFromTlab(size);
} else if (strategy_index == 1) {
return AllocateFromHeap(size);
}
return nullptr;
}
private:
std::vector<float> ExtractAllocationFeatures(size_t size) {
// 从系统状态和请求信息中提取特征
}
void SetInputTensorData(const std::vector<float>& data) {
// 设置模型输入张量
}
std::vector<float> GetOutputTensorData() {
// 获取模型输出张量
}
tflite::ops::builtin::BuiltinOpResolver resolver_;
std::unique_ptr<tflite::Interpreter> interpreter_;
};
通过分析历史内存使用数据和应用行为模式,机器学习模型可动态调整内存分配、垃圾回收策略,进一步提升内存使用效率和应用性能。