Coco2d-x 内存管理笔记

来源:互联网 发布:saga淘宝 编辑:程序博客网 时间:2024/06/16 19:31

Coco2d-x内存管理包括3个类,Ref(引用计数类)、AutoreleasePool(自动释放池)、PoolManager(自动释放池管理类)。

  • Ref:Ref是所有需要内存管理的类的基类,用于管理对象的引用计数。Ref中包含两种内存管理函数:手动管理函数retain()(引用计数加1)和release()(引用计数减1,当引用计数为0时,deleted this释放自身),自动管理类函数autorelease()(将对象自身交与PoolManager的栈顶AutoreleasePool管理,PoolManager会每帧都会release()一次所有autorelease对象)。
  • AutoreleasePool:AutoreleasePool是用于管理autorelease对象的管理类。本身是一个Vector,最少可以装150个对象(初始化reverse()了150个elements)。Ref中autorelease()调用的是PoolManager的栈顶的AutoreleasePool对象中的addObject()函数,将对象自身加入AutoreleasePool。PoolManager中每帧调用的是栈顶的AutoreleasePool对象的clear()函数release()一次全部autorelease对象(只是引用计数减1,不一定会delete)。
  • PoolManager:PoolManager是用于管理AutoreleasePool的一个管理类,它是一个单实例类,初始化可以包含10个池,其自身也是一个Vector,当作栈使用,一般来说PoolManager会用到的函数就只有getCurrentPool(),返回的是栈顶即Vector最后一个AutoreleasePool,因为一般来说只用一个AutoreleasePool就可以了,所以push(AutoreleasePool *pool)和pop()基本不会使用。


操作流程(以Scene为例子)

1.假设要新建一个场景:auto scene = Scene::create()

//--------------------------------------------------------------------//// Scene::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;    }}

在new一个Scene之后,调用该Scene的autorelease()函数,将该对象加入到自动释放池中

2.ret->autorelease();

//--------------------------------------------------------------------//// Ref:::autorelease()////--------------------------------------------------------------------Ref* Ref::autorelease(){    PoolManager::getInstance()->getCurrentPool()->addObject(this);    return this;}

该Scene的autorelease()函数中,第一次调用PoolManager的getInstance(),需要进行PoolManager的初始化

3.PoolManager初始化:PoolManager::getInstance()

//--------------------------------------------------------------------//// PoolManager:::getInstance()////--------------------------------------------------------------------PoolManager* PoolManager::getInstance(){    if (s_singleInstance == nullptr)    {        s_singleInstance = new (std::nothrow) PoolManager();        // Add the first auto release pool        new AutoreleasePool("cocos2d autorelease pool");    }    return s_singleInstance;}

初始化包括:new一个PoolManager和new一个名为cocos2d autorelease pool的默认AutoreleasePool。

//--------------------------------------------------------------------//// PoolManager:::PoolManager()////--------------------------------------------------------------------PoolManager::PoolManager(){    _releasePoolStack.reserve(10);}

new一个PoolManager会申请一个至少可以保存10个AutoreleasePool的数组并当作栈来使用,其实一般只需要用到1个AutoreleasePool

//--------------------------------------------------------------------//// AutoreleasePool:::AutoreleasePool()////--------------------------------------------------------------------AutoreleasePool::AutoreleasePool(const std::string &name): _name(name){    _managedObjectArray.reserve(150);    PoolManager::getInstance()->push(this);}
new一个AutoreleasePool会申请一个至少可以保存150个Ref类对象的数组,并把自身push到PoolManager的自动释放池栈的栈顶

//--------------------------------------------------------------------//// PoolManager:::push()////--------------------------------------------------------------------void PoolManager::push(AutoreleasePool *pool){    _releasePoolStack.push_back(pool);}

一般来说,PoolManager只会push一个默认的AutoreleasePool,不再需要其他的AutoreleasePool,所以PoolManager的自动释放池栈中一般只有一个elements

4.初始化PoolManager之后,获取栈顶的AutoreleasePool:PoolManager::getInstance()->getCurrentPool()

//--------------------------------------------------------------------//// AutoreleasePool:::getCurrentPool()////--------------------------------------------------------------------AutoreleasePool* PoolManager::getCurrentPool() const{    return _releasePoolStack.back();}
因为Vector当作栈使用,所以_releasePoolStack的尾部就是栈顶,返回尾部_releasePoolStack.back()

5.获取当前AutoreleasePool后,把该Scene加入AutoreleasePool: PoolManager::getInstance()->getCurrentPool()->addObject(this);

//--------------------------------------------------------------------//// AutoreleasePool:::addObject()////--------------------------------------------------------------------void AutoreleasePool::addObject(Ref* object){    _managedObjectArray.push_back(object);}
把该Scene加入_managedObjectArray尾部

6.autorelease对象会在mainLoop()中调用PoolManager::getInstance()->getCurrentPool()->clear()进行内存清理

//--------------------------------------------------------------------//// DisplayLinkDirector:::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();    }}
在draw所有的scene之后(一帧所有的rendering后),进行内存清理

//--------------------------------------------------------------------//// AutoreleasePool:::clear()////--------------------------------------------------------------------void AutoreleasePool::clear(){    std::vector<Ref*> releasings;    releasings.swap(_managedObjectArray);    for (const auto &obj : releasings)    {        obj->release();    }}

这里用到swap()函数releasings.swap(_managedObjectArray),大概就像交换两个vector的保存数据的内存首地址,然后AutoreleasePool中的_managedObjectArray的保存数据的内存首地址指向releasings的保存数据的内存首地址,两个vector中的内容交换后_managedObjectArray空了,releasings需要手动清空,即遍历releasings调用elements的release()进行内存清理。

7.swap()的使用方法

vector<int> vec(100000, 0);cout << "vec[0] = " <<vec[0] << "        ";cout << "vec[100000 - 1] = " << vec[100000 - 1] << endl;for (int i = 0; i < 100000 - 2; ++i) vec.pop_back();cout << "After pop_back() (100000 - 2) times , vec.capacity() = " << vec.capacity() << endl;vector<int>(vec).swap(vec);//vector<int>(vec)是用vec作为形参新建一个vector,此时vec只剩两个elements了,所以新建的vector容量为2cout << "After swap() with vector<int>(vec) (a new vector only have 2 elements), vec.capacity() = " << vec.capacity() << endl;



三个类的所有函数

//--------------------------------------------------------------------//// Ref////--------------------------------------------------------------------Ref::Ref(): _referenceCount(1) // when the Ref is created, the reference count of it is 1}Ref::~Ref(){ }void Ref::retain(){    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");    ++_referenceCount;}void Ref::release(){    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");    --_referenceCount;    if (_referenceCount == 0)    {        delete this;    }}Ref* Ref::autorelease(){    PoolManager::getInstance()->getCurrentPool()->addObject(this);    return this;}unsigned int Ref::getReferenceCount() const{    return _referenceCount;}//--------------------------------------------------------------------//// AutoreleasePool////--------------------------------------------------------------------AutoreleasePool::AutoreleasePool(): _name(""){    _managedObjectArray.reserve(150);    PoolManager::getInstance()->push(this);}AutoreleasePool::AutoreleasePool(const std::string &name): _name(name){    _managedObjectArray.reserve(150);    PoolManager::getInstance()->push(this);}AutoreleasePool::~AutoreleasePool(){    CCLOGINFO("deallocing AutoreleasePool: %p", this);    clear();    PoolManager::getInstance()->pop();}void AutoreleasePool::addObject(Ref* object){    _managedObjectArray.push_back(object);}void AutoreleasePool::clear(){    std::vector<Ref*> releasings;    releasings.swap(_managedObjectArray);    for (const auto &obj : releasings)    {        obj->release();    }}bool AutoreleasePool::contains(Ref* object) const{    for (const auto& obj : _managedObjectArray)    {        if (obj == object)            return true;    }    return false;}//--------------------------------------------------------------------//// PoolManager////--------------------------------------------------------------------PoolManager* PoolManager::s_singleInstance = nullptr;PoolManager* PoolManager::getInstance(){    if (s_singleInstance == nullptr)    {        s_singleInstance = new (std::nothrow) PoolManager();        // Add the first auto release pool        new AutoreleasePool("cocos2d autorelease pool");    }    return s_singleInstance;}void PoolManager::destroyInstance(){    delete s_singleInstance;    s_singleInstance = nullptr;}PoolManager::PoolManager(){    _releasePoolStack.reserve(10);}PoolManager::~PoolManager(){    CCLOGINFO("deallocing PoolManager: %p", this);    while (!_releasePoolStack.empty())    {        AutoreleasePool* pool = _releasePoolStack.back();        delete pool;    }}AutoreleasePool* PoolManager::getCurrentPool() const{    return _releasePoolStack.back();}bool PoolManager::isObjectInPools(Ref* obj) const{    for (const auto& pool : _releasePoolStack)    {        if (pool->contains(obj))            return true;    }    return false;}void PoolManager::push(AutoreleasePool *pool){    _releasePoolStack.push_back(pool);}void PoolManager::pop(){    CC_ASSERT(!_releasePoolStack.empty());    _releasePoolStack.pop_back();}


0 0
原创粉丝点击