在上一篇博客: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对象。
以上。