COCOS学习笔记--内存管理(二)-PoolManager类和AutoreleasePool类的讲解

在上一篇博客:Cocod2dx内存管理(一)--引用计数和Ref类的讲解

http://blog.csdn.net/gzy252050968/article/details/50459012

我们知道了Cocos2d-x中使用引用计数进行内存管理,并且Ref类中提供了 retain()、release()、autorelease()方法分,别用于增加计数、减少计数以及将一个对象交给自动释放池对象AutoreleasePool进行管理,由AutoreleasePool对象负责调用release函数,那么,内存管理类PoolManager以及自动释放池AutoreleasePool类具体是怎样进行管理的呢?


我们先来看CCAutoreleasePool,主要有以下方法:

AutoreleasePool();//构造
AutoreleasePool(const std::string &name);//构造函数的重载
~AutoreleasePool();//析构
void addObject(Ref *object);//将Ref添加到自动释放池
void clear();//清除自动释放池所有对象
bool contains(Ref* object) const;//检测自动释放池中是否有Object对象
void dump();//打印删除的对象的地址

我们来一个一个看:

构造函数:

AutoreleasePool::AutoreleasePool()
    : _name("")//设置名字为””
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        , _isClearing(false)//设置sClearing为false
    #endif
    {	//容器扩容,申请保存ref的vector的size增加150
        _managedObjectArray.reserve(150);
        //把AutoreleasePool添加到管理类生明的vector中
        PoolManager::getInstance()->push(this);
    }

构造函数中我们可以看到每一个自动释放池AutoreleasePool的对象都有一个管理obj的队列managedObjectArray用于存放池中的obj,并且所有的AutoreleasePool对象都是放在PoolManager的单例对象的一个堆中的,这个一会我们看PoolManager类的代码就可以知道。

析构函数:

AutoreleasePool::~AutoreleasePool()
{
    CCLOGINFO("deallocing AutoreleasePool: %p", this);
    //清除
    clear();
    //弹出
    PoolManager::getInstance()->pop();
}

注意AutoreleasePool析构函数是先清除自动释放池所有obj对象,然后再将自己从PoolManager单例的堆里弹出。

把object添加到managedObjectArray自动释放池:

void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}

看到了吧,每个AutoreleasePool对象都为维护着一个队列managedObjectArray,里面可以放好多好多的obj。

clear()方法就是AutoreleasePool对象把自己维护的队列managedObjectArray里面每一个obj都执行release():

void AutoreleasePool::clear()
{
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        _isClearing = true;//设置为执行了清空操作
    #endif
    std::vector<Ref*> releasings;
    releasings.swap(_managedObjectArray);
    //遍历自动释放池managedObjectArray里存放的所有的Ref
    for (const auto &obj : releasings)
    {
        //调用obj的release(),对obj的引用计数-1(如果对象引用计数为0则删除)
        obj->release();
    }
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        _isClearing = false;//设置为未执行清空操作
    #endif
}

剩下两个方法不多说了,看注释就行:

contains()方法判断自动释放池中是否含有某Ref:

bool AutoreleasePool::contains(Ref* object) const
{
    //遍历自动释放池managedObjectArray
    for (const auto& obj : _managedObjectArray)
    {
        //如果相等
        if (obj == object)
            //return true表示自动释放池managedObjectArray中有该对象
            return true;
     }
    return false;
}

打印自动释放池中各节点信息:

void AutoreleasePool::dump()
{
    //打印自动释放池managedObjectArray的size,用于调试
    CCLOG("autorelease pool: %s, number of managed object %d\n", _name.c_str(), static_cast<int>(_managedObjectArray.size()));
    CCLOG("%20s%20s%20s", "Object pointer", "Object id", "reference count");
    for (const auto &obj : _managedObjectArray)
    {
        CC_UNUSED_PARAM(obj);
        //打印对象的引用计数
        CCLOG("%20p%20u\n", obj, obj->getReferenceCount());
    }
}

好了,接下来看PoolManager类,这个类是用来管理AutoreleasePool的。

先看一下头文件这个类里都有什么:

class CC_DLL PoolManager
{
public:
 
    CC_DEPRECATED_ATTRIBUTE static PoolManager* sharedPoolManager() { return getInstance(); }
    static PoolManager* getInstance();//获得PoolManager实例对象,注意这是一个单例对象
    CC_DEPRECATED_ATTRIBUTE static void purgePoolManager() { destroyInstance(); }
    static void destroyInstance();//销毁PoolManager实例对象   
    AutoreleasePool *getCurrentPool() const;//获得当前的autoreleasepool   
    bool isObjectInPools(Ref* obj) const;//判断某obj是否在autoreleasepool中
    friend class AutoreleasePool;//把AutoreleasePool设置成友元类
 
    
private:
    PoolManager();
    ~PoolManager();
    void push(AutoreleasePool *pool); //加入
    void pop();//弹出
    static PoolManager* s_singleInstance; //poolmanager的实例,再强调一遍这是个单例对象
    std::vector<AutoreleasePool*> _releasePoolStack;//看这里!这就是poolmanager实例维护的堆,用来保存所有AutoreleasePool对象
};


那么接下来我们去看看PoolManager类以上这些方法的具体实现:

首先设置了PoolManager的单例对象singleInstance 为nullptr:

PoolManager* PoolManager::s_singleInstance = nullptr;

获得PoolManager的单例对象方法:

PoolManager* PoolManager::getInstance()
{
    //判断是否存在singleInstance 
    if (s_singleInstance == nullptr)
    {
        //如果singleInstance 为nullptr,new一个PoolManager单例
        s_singleInstance = new (std::nothrow) PoolManager();
        //new一个AutoreleasePool并取名字为"cocos2d autorelease pool"
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}

此方法可以获得PoolManager的单例对象,如果没有就new一个,什么是单例对象?就是整个工程里这个类只有这一个实例对象,这是设计模式里的单例模式之饿汉式我之前的博客里也有介绍过,有兴趣的可以看看。

注意该方法里有一句代码:    

new AutoreleasePool("cocos2d autorelease pool");

这句代码十分重要,这是在PoolManager类 的getInstance()方法中创建了一个AutoreleasePool,也就是说我们通过getInstance()获得PoolManager对象时其实它已经绑定了一个AutoreleasePool对象,这个AutoreleasePool的名字叫"cocos2d autorelease pool",这是我们系统创建的第一个AutoreleasePool,因为引擎的运行机制是在Cocos项目刚启动时就会调用PoolManager::getInstance(),所以这里可以说明一个问题,就是这个叫做"cocos2d autorelease pool"的自动释放池对象是用来保存大部分渲染的节点以及我们通过create()创建的对象,它是Cocos2d-x中使用频率最高的AutoreleasePool。

删除PoolManager单例对象:

void PoolManager::destroyInstance()
{
    delete s_singleInstance;
    s_singleInstance = nullptr;
}

构造函数:

PoolManager::PoolManager()
{
    //增加releasePoolStack容器的size
    //这个容器存放所有的AutoreleasePool对象
    _releasePoolStack.reserve(10);
}

析构函数:

PoolManager::~PoolManager()
{
    CCLOGINFO("deallocing PoolManager: %p", this);
    
    while (!_releasePoolStack.empty())
   {
        //获得最后一个AutoreleasePool对象
        AutoreleasePool* pool = _releasePoolStack.back();
        //删除
        delete pool;
    }
}

PoolManager的析构函数是从其维护的堆releasePoolStack的末尾开始,一个一个地删除掉AutoreleasePool对象。

获得当前的AutoreleasePool对象:

AutoreleasePool* PoolManager::getCurrentPool() const
{
    //得到的是最后添加到PoolManager中的AutoreleasePool对象
    return _releasePoolStack.back();
}

判断某obj是否在其堆中存放的AutoreleasePool里:

bool PoolManager::isObjectInPools(Ref* obj) const
{
    //遍历所有的AutoreleasePool
    for (const auto& pool : _releasePoolStack)
   {
        //如果pool中存在obj,返回true
        if (pool->contains(obj))
            return true;
    }
    return false;
}

向PoolManager中添加一个pool:

//在其堆的末尾添加
void PoolManager::push(AutoreleasePool *pool)
{
    _releasePoolStack.push_back(pool);
}

删除PoolManager堆末尾的pool:

void PoolManager::pop()
{
    CC_ASSERT(!_releasePoolStack.empty());
    _releasePoolStack.pop_back();
}

好了,至此PoolManager类和AutoreleasePool类我们就讲解完了。



最后总结一下:

1.每一个自动释放池AutoreleasePool类对象中都维护着一个队列managedObjectArray,用来存放一些Ref对象obj;

2.AutoreleasePool类提供了addObject()、clear()、contains()、dump()等方法用于管理其池中的obj;

3.在AutoreleasePool::clear()方法中调用了Ref::release()方法;

4.PoolManager类对象是一个单例对象singleInstance ,整个工程中只有一个;

5.PoolManager类维护着一个堆releasePoolStack,用来存放工程中所有的AutoreleasePool对象;

6.名字叫"cocos2d autorelease pool"的自动释放池对象保存工程中大部分渲染的节点以及我们通过create()创建的对象,这个AutoreleasePool对象是工程刚启动时就生成的;

7.PoolManager类提供了getInstance()、destroyInstance()、getCurrentPool()、isObjectInPools()、push()、pop()等方法管理所有的自动释放池AutoreleasePool对象。

 



以上。



你可能感兴趣的:(内存管理,cocos2d-x,自动释放池,autoReleasePool,PoolManager)