c++的内存管理一直以来都是个问题,也有多种实现方案,比如智能指针,使用引用计数等,cocos2d-x也需要涉及到内存的管理。
cocos2d-x是如何管理内存的呢?
cocos2d-x的内存管理主要使用引用计数的机制进行内存的自动管理或者手动管理
常用的谁 new 了,谁delete 。这种方式很容易造成内存的碎片,严重的可能会造成内存的泄露,因为不是每个程序员都会记得在哪释放
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 , m_uReference == 0时,delete this,销毁自己 void retain(void); // 自增1 , m_uReference++ ; CCObject* autorelease(void); // 自动内存管理的。CCPoolManager::sharedPoolManager()->addObject(this);CCPoolManager是个内存池管理的 CCObject* copy(void); // CCObject的拷贝机制,内部就一句代码 return copyWithZone(0); ,可见,是调用了copyWithZone 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; // 把CCAutoreleasePool设为CCObject的友元类,是为了方便CCAutoreleasePool访问CCObject中的成员进而进行内存管理 };
成员变量 m_uID 和 m_nLuaID 是关于支持lua脚本语言用的。暂时可以不用管
成员变量 m_uReference 为此类的一个实例引用的次数,初始化为 1 ,如果为0,则表明此实例没有被任何对象引用,则可以删除 , delete this
成员变量 m_uAutoReleaseCount 为此类的一个实例是否是自动释放内存的。初始化0,如果大于0,则表明是自动释放的。此前的cocos2d-x版本中,m_uAutoReleaseCount 是个bool类型的变量。
看下 CCObject 的类的实现代码:如下,有注释
CCObject::CCObject(void) : m_nLuaID(0) // 支持lua脚本语言的,初始化为 0 , m_uReference(1) // 当创建一个CCObject对象时,引用计数加 1 , m_uAutoReleaseCount(0) // 自动释放内存的标识位, 等于0则表明不会自动释放,大于0表示对象会自动释放内存 { static unsigned int uObjectCount = 0; m_uID = ++uObjectCount; } CCObject::~CCObject(void) { // 如果此对象已经具有自动释放内存机制,则把此对象从内存池中删除掉 if (m_uAutoReleaseCount > 0) { CCPoolManager::sharedPoolManager()->removeObject(this);//把此对象从内存池中删除掉 } //下面是支持lua脚本语言相关的 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() { //copy函数,直接调用copyWithZone,在这里没有用到 return copyWithZone(0); } //释放内存 void CCObject::release(void) { CCAssert(m_uReference > 0, "reference count should greater than 0"); --m_uReference; //对象的引用计数减 1 if (m_uReference == 0)//如果引用计数为0,表明没有其它对象引用了,就删除对象,释放内存 { delete this; } } void CCObject::retain(void) { CCAssert(m_uReference > 0, "reference count should greater than 0"); ++m_uReference; //如果引用一次,就要手动调用retain,把对象的引用加1 } CCObject* CCObject::autorelease(void) { //新创建的对象如果调用autorelease()函数,就把此对象加入到内存池管理器,此后就可以不再关心内存的释放了。 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); }
CCObject实现了内存的自动管理机制(autorelease())和内存释放(release())机制
接下来,介绍一下两个与内存管理相关的类 CCPoolManager和CCAutoreleasePool