Cocos2d-x 引用计数内存管理核心机制解析
C++ 内存管理一直是开发中的难点,常见方案包括智能指针和引用计数等。Cocos2d-x 引擎也提供了自己的内存管理策略,主要通过引用计数来实现自动或手动内存控制。
与传统的 "谁 new 谁 delete" 模式不同,Cocos2d-x 的内存管理可以避免内存碎片和泄漏问题。传统方式容易因为开发者忘记释放内存而导致问题,而 Cocos2d-x 提供了更灵活的机制。
Cocos2d-x 的内存管理分为两种模式:手动管理和自动管理。核心类是 CCObject,它实现了引用计数的管理逻辑。
查看 CCObject 的源码,其关键成员和接口如下:
class CC_DLL CCObject : public CCCopying
{
public:
// 用于脚本语言(如 Lua)的支持,可暂时忽略
unsigned int m_uID;
int m_nLuaID;
protected:
unsigned int m_uReference; // 对象的引用计数
unsigned int m_uAutoReleaseCount; // 自动释放计数
public:
CCObject(void);
virtual ~CCObject(void);
void release(void); // 引用计数减1,若为0则 delete this
void retain(void); // 引用计数加1
CCObject* autorelease(void); // 将对象加入自动释放池
CCObject* copy(void); // 内部调用 copyWithZone(0)
bool isSingleReference(void) const; // 检查是否只有一个引用
unsigned int retainCount(void) const; // 返回当前引用数
virtual bool isEqual(const CCObject* pObject); // 比较两个对象是否相同
virtual void acceptVisitor(CCDataVisitor &visitor);
virtual void update(float dt) {CC_UNUSED_PARAM(dt);}
friend class CCAutoreleasePool; // 友元类,便于内存管理
};
m_uID 和 m_nLuaID 主要用于 Lua 等脚本绑定,此处暂不讨论。
m_uReference 表示该对象的引用次数,初始值为 1。当引用计数为 0 时,说明该对象不再被任何地方使用,可以删除。
m_uAutoReleaseCount 用于标记是否启用自动释放机制。初始值为 0,表示不自动释放;大于 0 则代表该对象由自动释放池管理。在早期版本中,此字段为 bool 类型。
下面是 CCObject 核心方法的实现细节:
CCObject::CCObject(void)
: m_nLuaID(0)
, m_uReference(1) // 新对象引用计数从1开始
, m_uAutoReleaseCount(0) // 默认不自动释放
{
static unsigned int uObjectCount = 0;
m_uID = ++uObjectCount;
}
CCObject::~CCObject(void)
{
// 如果对象启用了自动释放,将其从池中移除
if (m_uAutoReleaseCount > 0)
{
CCPoolManager::sharedPoolManager()->removeObject(this);
}
// 清理脚本引擎相关绑定
if (m_nLuaID)
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptObjectByCCObject(this);
}
else
{
CCScriptEngineProtocol* pEngine = CCScriptEngineManager::sharedManager()->getScriptEngine();
if (pEngine != NULL && pEngine->getScriptType() == kScriptTypeJavascript)
{
pEngine->removeScriptObjectByCCObject(this);
}
}
}
CCObject* CCObject::copy()
{
return copyWithZone(0);
}
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
void CCObject::retain(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
++m_uReference;
}
CCObject* CCObject::autorelease(void)
{
// 将对象加入自动释放池,后续由池管理内存
CCPoolManager::sharedPoolManager()->addObject(this);
return this;
}
bool CCObject::isSingleReference(void) const
{
return m_uReference == 1;
}
unsigned int CCObject::retainCount(void) const
{
return m_uReference;
}
bool CCObject::isEqual(const CCObject *pObject)
{
return this == pObject;
}
void CCObject::acceptVisitor(CCDataVisitor &visitor)
{
visitor.visitObject(this);
}
通过 autorelease() 和 release(),CCObject 实现了自动与手动两种内存管理模式。
接下来介绍与内存管理相关的另外两个关键类:CCPoolManager 和 CCAutoreleasePool。