作者:小薇虫虫_851_413 | 来源:互联网 | 2017-05-12 15:45
Cocos2d-x中的内存管理现有的智能内存管理技术:(1)引用计数,存在堆碎片化和管理繁琐的问题;(2)垃圾回收。Cocos2d-x巧妙运用了前面的引用计数机制,在CCObject.h头文件中,看到CCObject的定义classCC_DLLCCObject:publicCCCopying{public:
Cocos2d-x中的内存管理 现有的智能内存管理技术:(1)引用计数,存在堆碎片化和管理繁琐的问题;(2)垃圾回收。 Cocos2d-x巧妙运用了前面的引用计数机制,在CCObject.h头文件中,看到CCObject的定义 class CC_DLL CCObject : public CCCopying{public: //
Cocos2d-x中的内存管理
现有的智能内存管理技术:(1)引用计数,存在堆碎片化和管理繁琐的问题;(2)垃圾回收。
Cocos2d-x巧妙运用了前面的引用计数机制,在CCObject.h头文件中,看到CCObject的定义
class CC_DLL CCObject : public CCCopying
{
public:
// object id, CCScriptSupport need public m_uID 对象id,在脚本引擎中使用
unsigned int m_uID; Lua中的引用id,被脚本使用
// Lua reference id
int m_nLuaID;
protected:
// count of references
unsigned int m_uReference; //引用数量
// count of autorelease
unsigned int m_uAutoReleaseCount; //是否设置为autorelease,自动回收池
public:
CCObject(void);
virtual ~CCObject(void);//虚析构函数
void release(void); //在其他地方引用,m_uReference自动加1
void retain(void); //引用结束,m_uReference自动减1 CCObject* autorelease(void);//将对象自动放入回收池,当回收池自身被释放时,对池中的所有对象执行release()方法
CCObject* copy(void); bool isSingleReference(void); unsigned int retainCount(void); virtual bool isEqual(const CCObject* pObject); virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; friend class CCAutoreleasePool;};
执行一次autorelease()后对象的引用并没有被立刻释放,在下一帧开始之前,对象被释放。
但是考虑到效率问题,如果在一帧过程中生成了大量autorelease对象,导致回收池性能下降,因此在使用autorelease()密集的地方,可以手动设置一个回收池。如下:
CCPoolManger::sharedPoolManager()->push();
for(int i = 0;i addObject(dataItem);
}
CCPoolManager::sharedPoolManager()->pop();
代码执行n次循环,每次都会创建一个autorelease对象CCString,为了保持回收池的性能,在循环前使用push方法创建了一个新的回收池,在循环结束后使用pop方法释放刚才的回收池。
工厂方法:
工厂方法是程序设计中一个经典的设计模式,指的是类中定义创建对象的接口,将实际实现推迟到子类中。分析如下代码:
CCObject* factoryMethod()
{
CCObject* ret = new CCobject();
return ret;
}
返回ret时ret指向的内存被释放。用autorelease()解决了这个问题。虽然调用了autorelease,但对象并未直接被释放掉,而是在一帧结束后释放回收池。修改后的代码
CCObject* factoryMethod()
{
CCObject* ret = new CCobject();
ret->autorelease();
return ret;
}
使用工厂方法创建的对象,虽然引用计数也为1,但是由于对象已经被放入回收池,因此调用者没有该对象的引用权,除非我们认为调用retain()来获取引用权,否则不用主动释放对象。
关于传值:
将一个对象赋值给某一指针作为引用的时候,为了遵循内存管理的原则,我们需要获取新对象的引用权,释放就对象的引用权。release()和retain()的顺序尤为重要。
如下代码:
//错误代码
void SomeClass::setObject(CCObject* other)
{
this->object->release();
other->retain();
this->object = other;
}
//完善后代码
void SomeClass::setObject(CCObject* other)
{
other->retain();
this->object->release();
this->object = other;
}
第一个错误,当other和object指向同一个对象时,第一个release就会将对象回收,所以先执行retain()来保证other对象有效,在释放旧对象。
autorelease()只有在自动释放时才会进行一次释放操作,如果对象释放次数超过了应有次数,这个错误并不会被发现,只有当自动释放池被释放时才会崩溃。定位错误就很困难了。因此在开发中尽量避免滥用autorelease(),只在工厂方法等不得不用的情况下使用,尽量以release()来释放对象引用。
容器:CCArray、CCdictionary,如果直接使用STL容器,开发者需进行繁琐的内存管理操作,Cocos2d-x对这一过程进行了封装。
相关辅助宏:包含在头文件CCPlatformMacro.h里
Cocos2d-x中与内存管理有关的宏
宏 |
描述 |
CC_SAFE_DELETE(p) |
使用delete操作符删除一个C++对象p,如果p为NULL,则不进行操作 |
CC_SAFE_DELETE_ARRAY(p) |
使用delete[]操作符删除一个C++数组p,如果p为NULL,则不进行操作 |
CC_SAFE_FREE(p) |
使用free()函数删除p,如果p为NULL,则不进行操作 |
CC_SAFE_RELEASE(p) |
使用release()方法释放p的一次引用,如果p为NULL,则不进行操作 |
CC_SAFE_RELEASE_NULL(p) |
使用release()方法释放p的一次引用,再把p赋值为NULL,如果p已经为NULL,则不进行操作 |
CC_SAFE_RETAIN(p) |
使用retain()方法增加p的一次引用,如果p为NULL,则不进行操作 |
Cocos2d-x内存管理原则:
(1)程序段必须成对执行retain()和release()或者执行autorelease()来开始和结束对象的引用。
(2)工厂方法返回前,应通过autorelease()结束对该对象的引用。
(3)对象传值时,应考虑到新旧对象相同的特殊情况
(4)尽量使用release()而不是autorelease()释放对象引用,以确保性能最优。
(5)保存CCObject的子类对象时,应严格使用Cocos2d-x提供的容器,避免使用STL容器,对象必须以指针形式存入。