cocos2d-x 3.x对象创建采用create方式:如
Scene* Scene::create()
{
Scene *ret = new (std::nothrow) Scene();
if (ret && ret->init())
{
ret->autorelease(); // 自动释放内存
return ret;
}
else
{
CC_SAFE_DELETE(ret);
return nullptr;
}
}
在Scene new完之后,调用autorelease()方法,之后我们就不用操心Scene的内存释放问题了。
autorelease()方法:
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this); // 关键PoolManager
return this;
}
进到自动释放池
void AutoreleasePool::addObject(Ref* object)
{
_managedObjectArray.push_back(object);
}
这里有个clear方法:
void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = true;
#endif
for (const auto &obj : _managedObjectArray)
{
obj->release();
}
_managedObjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
_isClearing = false;
#endif
}
release()方法:
void Ref::release()
{
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
auto poolManager = PoolManager::getInstance();
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
{
// Trigger an assert if the reference count is 0 but the Ref is still in autorelease pool.
// This happens when 'autorelease/release' were not used in pairs with 'new/retain'.
//
// Wrong usage (1):
//
// auto obj = Node::create(); // Ref = 1, but it's an autorelease Ref which means it was in the autorelease pool.
// obj->autorelease(); // Wrong: If you wish to invoke autorelease several times, you should retain `obj` first.
//
// Wrong usage (2):
//
// auto obj = Node::create();
// obj->release(); // Wrong: obj is an autorelease Ref, it will be released when clearing current pool.
//
// Correct usage (1):
//
// auto obj = Node::create();
// |- new Node(); // `new` is the pair of the `autorelease` of next line
// |- autorelease(); // The pair of `new Node`.
//
// obj->retain();
// obj->autorelease(); // This `autorelease` is the pair of `retain` of previous line.
//
// Correct usage (2):
//
// auto obj = Node::create();
// obj->retain();
// obj->release(); // This `release` is the pair of `retain` of previous line.
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
}
#endif
#if CC_REF_LEAK_DETECTION
untrackRef(this);
#endif
delete this; //重点
}
}
我们终于见到了delete,这里判断引用计数_referenceCount 为0时,则delete对象(注cocos2d-x 对象都继承Ref类),释放内存。(引用计数增加,参见Ref::retain());
我们回到自动释放内存池的clear方法,哪里调用它呢?
找到了Director的mainloop方法:
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (_restartDirectorInNextLoop)
{
_restartDirectorInNextLoop = false;
restartDirector();
}
else if (! _invalid)
{
drawScene(); // 绘制场景
// release the objects
//释放自动内存池管理器里面暂时存储的对象,
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
mainloop调用:
int Application::run()
{
...
while(!glview->windowShouldClose())
{
QueryPerformanceCounter(&nNow);
if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);
director->mainLoop();
glview->pollEvents();
}
else
{
Sleep(1);
}
}
...
return true;
}
Application::run方法有一个死循环,由此可以看到自动内存管理对象在每帧绘制结束后都会被释放(此时如果对象的引用计数为0,即没有调用retain方法,就会被delete)。