Cocos2d-x 内存管理机制:自动释放池与池管理器的底层实现
自动释放池 CCAutoreleasePool 的核心机制
在 Cocos2d-x 的内存管理体系中,CCAutoreleasePool 扮演着对象收集器的角色。它的核心本质是对 CCArray 的封装,用于集中存储那些被标记为需要自动释放的对象引用。当对象调用 autorelease() 时,实际上是被添加到了当前活动的自动释放池中。
类定义与接口设计
CCAutoreleasePool 提供了添加、移除以及清理对象的核心接口。以下是重构后的类定义,优化了成员变量的命名规范以提升代码可读性:
class CC_DLL CCAutoreleasePool : public CCObject
{
private:
CCArray* _managedObjects; // 存储需要自动释放的对象集合
public:
CCAutoreleasePool();
~CCAutoreleasePool();
// 将目标对象加入自动释放池
void addObject(CCObject* targetObj);
// 从池中移除特定对象
void removeObject(CCObject* targetObj);
// 清空池内所有对象并触发释放逻辑
void clear();
};
底层实现逻辑
在实现层面,向池中添加对象时,需要妥善处理引用计数与自动释放标识。清理池时,则采用逆序遍历的方式以确保对象释放顺序的正确性。
CCAutoreleasePool::CCAutoreleasePool()
{
_managedObjects = new CCArray();
_managedObjects->init();
}
CCAutoreleasePool::~CCAutoreleasePool()
{
CC_SAFE_DELETE(_managedObjects);
}
void CCAutoreleasePool::addObject(CCObject* targetObj)
{
_managedObjects->addObject(targetObj);
// 确保对象的引用计数在加入池之前已经被 retain
CCAssert(targetObj->m_uReference > 1, "Reference count must be greater than 1");
// 增加自动释放计数标识
++(targetObj->m_uAutoReleaseCount);
// 抵消 addObject 带来的隐式 retain,恢复引用计数平衡
targetObj->release();
}
void CCAutoreleasePool::removeObject(CCObject* targetObj)
{
// 根据自动释放计数,将对象从底层数组中彻底移除
for (unsigned int i = 0; i < targetObj->m_uAutoReleaseCount; ++i)
{
_managedObjects->removeObject(targetObj, false);
}
}
void CCAutoreleasePool::clear()
{
if (_managedObjects->count() > 0)
{
CCObject* obj = nullptr;
// 采用逆序遍历,保证后加入的对象先被处理,避免依赖关系导致的崩溃
CCARRAY_FOREACH_REVERSE(_managedObjects, obj)
{
if (!obj) break;
--(obj->m_uAutoReleaseCount);
}
// 批量移除所有元素
_managedObjects->removeAllObjects();
}
}
内存池管理器 CCPoolManager 的栈式调度
由于游戏运行过程中可能存在多个场景或独立的逻辑上下文,单一的自动释放池无法满足复杂的内存隔离需求。因此,Cocos2d-x 引入了 CCPoolManager。该类采用单例模式,并利用 CCArray 模拟栈结构(Stack)来管理多个 CCAutoreleasePool 实例。栈顶元素即为当前正在使用的活动内存池。
管理器类定义
CCPoolManager 负责内存池的压栈、弹栈以及对象的转发调度。
class CC_DLL CCPoolManager
{
private:
CCArray* _poolStack; // 模拟栈结构的数组
CCAutoreleasePool* _currentPool; // 指向栈顶的活动内存池
CCAutoreleasePool* getCurrentPool();
public:
CCPoolManager();
~CCPoolManager();
// 清理栈中所有内存池
void finalize();
// 创建新内存池并压栈
void push();
// 弹出并销毁栈顶内存池
void pop();
void removeObject(CCObject* targetObj);
void addObject(CCObject* targetObj);
static CCPoolManager* sharedPoolManager();
static void purgePoolManager();
friend class CCAutoreleasePool;
};
栈操作与调度实现
管理器的核心在于维护栈的平衡。每次 push() 都会实例化一个新的内存池并将其置于栈顶;而 pop() 则会清理当前栈顶池并将其移除,使次栈顶元素成为新的活动池。
static CCPoolManager* s_sharedPoolManager = nullptr;
CCPoolManager* CCPoolManager::sharedPoolManager()
{
if (s_sharedPoolManager == nullptr)
{
s_sharedPoolManager = new CCPoolManager();
}
return s_sharedPoolManager;
}
void CCPoolManager::purgePoolManager()
{
CC_SAFE_DELETE(s_sharedPoolManager);
}
CCPoolManager::CCPoolManager()
{
_poolStack = new CCArray();
_poolStack->init();
_currentPool = nullptr;
}
CCPoolManager::~CCPoolManager()
{
finalize();
_currentPool = nullptr;
if (_poolStack->count() > 0)
{
_poolStack->removeObjectAtIndex(0);
}
CC_SAFE_DELETE(_poolStack);
}
void CCPoolManager::finalize()
{
if (_poolStack->count() > 0)
{
CCObject* obj = nullptr;
CCARRAY_FOREACH(_poolStack, obj)
{
if (!obj) break;
CCAutoreleasePool* pool = static_cast(obj);
pool->clear();
}
}
}
void CCPoolManager::push()
{
CCAutoreleasePool* newPool = new CCAutoreleasePool();
_currentPool = newPool;
// 加入栈中,内部会触发 retain
_poolStack->addObject(newPool);
// 释放初始引用,交由栈管理生命周期
newPool->release();
}
void CCPoolManager::pop()
{
if (!_currentPool) return;
int stackSize = _poolStack->count();
// 触发当前栈顶池的清理逻辑
_currentPool->clear();
if (stackSize > 1)
{
_poolStack->removeObjectAtIndex(stackSize - 1);
_currentPool = static_cast(_poolStack->objectAtIndex(stackSize - 2));
}
else
{
_currentPool = nullptr;
}
}
void CCPoolManager::removeObject(CCObject* targetObj)
{
CCAssert(_currentPool, "Current autorelease pool should not be null");
_currentPool->removeObject(targetObj);
}
void CCPoolManager::addObject(CCObject* targetObj)
{
getCurrentPool()->addObject(targetObj);
}
CCAutoreleasePool* CCPoolManager::getCurrentPool()
{
// 若栈为空,则自动初始化一个默认池
if (!_currentPool)
{
push();
}
CCAssert(_currentPool, "Current autorelease pool should not be null");
return _currentPool;
}
协同工作机制
通过上述源码重构与解析可以看出,Cocos2d-x 的自动释放机制依赖于这两个类的紧密配合。CCAutoreleasePool 专注于微观层面的对象引用收集与计数维护,而 CCPoolManager 则从宏观层面利用栈结构实现了内存池的生命周期调度与上下文隔离。当引擎主循环进入帧末尾时,管理器会调用当前栈顶内存池的 clear() 方法,从而统一执行延迟释放操作,确保内存的高效回收与游戏运行的稳定性。