cocos2d-x源码中的内存管理
cocos2d-x的内存管理原则——引用计数机制
内存管理:引用计数机制, 当一个对象执行retain操作的时候,引用计数加1,当执行release操作的时候,引用计数减1,当引用计数为0时,此对象被释放。
通过基类Ref的代码实现,便可以明白基本的内存管理机制,直接打开 CCRef.cpp
文件
// 我们直接来看看CCRef.cpp文件
Ref::Ref()
: _referenceCount(1) //注:当Ref对象被创建,此对象的引用计数为1
void Ref::retain() //retain方法
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
++_referenceCount; //引用计数加1
}
void Ref::release() //release方法
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
--_referenceCount; //引用计数减1
if (_referenceCount == 0) //当引用计数为0的时候,删除对象
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
auto poolManager = PoolManager::getInstance();
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
{
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
}
#endif
delete this; //删除对象!!!
}
}
Ref* Ref::autorelease() //autorelease方法
{
PoolManager::getInstance()->getCurrentPool()->addObject(this); //将对象加入到自动释放池中
return this;
}
unsigned int Ref::getReferenceCount() const
{
return _referenceCount; //获取引用计数个数
}
通过看Ref类的源码,可以得出结论:
1.当一个对象被创建的时候,将此对象的引用计数设置为1
2.当执行一次retain,引用计数加1,
3.执行一次release,引用计数减1
4.当引用计数为0的时候,此对象被释放delete
Ref的autorelease方法
Ref* Ref::autorelease() //autorelease方法
{
PoolManager::getInstance()->getCurrentPool()->addObject(this); //将对象加入到自动释放池中
return this;
}
什么时候调用autorelease方法?
Label* Label::create()
{
auto ret = new (std::nothrow) Label;
if (ret)
{
ret->autorelease(); //create函数里,会自动执行autorelease方法
}
return ret;
}
可以看出,在create函数里,会自动执行autorelease方法, 也就是加入到自动释放池
AutoreleasePool
自动释放池:
它有个属性_managedObjectArray,可以将执行了autorelease方法的Ref对象加入_managedObjectArray,当AutoreleasePool::clear()时,也就是对_managedObjectArray中的每一项执行release操作
PoolManager
自动释放池管理类
有个生成器属性_releasePoolStack,里面加入的都是AutoreleasePool的对象,可以获取当前的AutoreleasePool
可以看到实现是建立了一个PoolManager的单例,接下来看看PoolManager,有个生成器属性_releasePoolStack
PoolManager* PoolManager::s_singleInstance = nullptr;
PoolManager* PoolManager::getInstance()
{ //PoolManager是个单例
if (s_singleInstance == nullptr)
{
s_singleInstance = new (std::nothrow) PoolManager();
// Add the first auto release pool
new AutoreleasePool("cocos2d autorelease pool");
}
return s_singleInstance;
}
AutoreleasePool* PoolManager::getCurrentPool() const
{
return _releasePoolStack.back(); //_releasePoolStack最后的一个AutoreleasePool对象
}
//注意接下来的两个函数:push,pop
void PoolManager::push(AutoreleasePool *pool)
{
_releasePoolStack.push_back(pool); //在_releasePoolStack这个vector尾部加入pool
}
void PoolManager::pop()
{
CC_ASSERT(!_releasePoolStack.empty());
_releasePoolStack.pop_back();//删除_releasePoolStack最后一个元素
}
PoolManager::getInstance()->getCurrentPool()->addObject(this)中的getCurrentPool可以看出获取到了一个AutoreleasePool对象,然后我们查看AutoreleasePool
class CC_DLL AutoreleasePool
{
private:
std::vector<Ref*> _managedObjectArray; //AutoreleasePool有个生成器属性_managedObjectArray,用来装Ref对象
};
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}
void AutoreleasePool::clear() //清楚操作
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
std::vector<Ref*> releasings;
releasings.swap(_managedObjectArray); //遍历_managedObjectArray,为每一个对象执行release操作
for (const auto &obj : releasings)
{
obj->release();
}
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}
PoolManager::getInstance()->getCurrentPool()->addObject(this)中的addObject其实就是给_managedObjectArray这个vector中添加一个Ref对象
可以看到AutoreleasePool::clear()的方法实现,其实是把_managedObjectArray里面的每一个对象执行一次release操作,clear函数会在DisplayLinkDirector
的mainLoop函数中被调用,一帧调用一次,及时回收。
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (_restartDirectorInNextLoop)
{
_restartDirectorInNextLoop = false;
restartDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects !!!在此处执行clear操作
PoolManager::getInstance()->getCurrentPool()->clear();
}
}