Cocos2d-x使用的内存管理方式是引用计数,引用计数是一种很有效的机制,通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数。当对象增加一次引用时,计数器加1;而对象失去一次引用时,计数器减1;当引用计数为0时,标志着该对象的生命周期结束,自动触发对象的回收释放。引用计数的重要规则是每一个程序片段必须负责任地维护引用计数,在需要维持对象生存的程序段的开始和结束分别增加和减少一次引用计数,这样就可以实现十分灵活的内存管理。
接下来看一下Cocos2d-x 3.1 版本的源码是怎么实现引用计数的。
一、Ref
我们都知道几乎每个类都继承一个类Ref,打开CCRef.h查看Ref类,去掉其它与引用计数无关的,可以简化为:
// CCRef.hclass CC_DLL Ref{public: voID retain(); // 引用计数加1 voID release(); // 引用计数减1 Ref* autorelease(); // 将对象交给自动释放池 unsigned int getReferenceCount() const; // 获取当前的引用计数 protected: Ref(); // 构造函数,这里的权限为protected,说明自己不能实例化,子类可以实例化 public: virtual ~Ref(); protected: unsigned int _referenceCount; // 引用计数 frIEnd class autoreleasePool; // 这个先别管};
// CCRef.cppRef::Ref(): _referenceCount(1) // new一个对象时,引用计数加1{} Ref::~Ref(){} voID Ref::retain(){ CCASSERT(_referenceCount > 0,"reference count should greater than 0"); ++_referenceCount;} voID Ref::release(){ CCASSERT(_referenceCount > 0,"reference count should greater than 0"); --_referenceCount; if (_referenceCount == 0) // 引用为0时说明没有调用该对象,此时delete对象 { delete this; }} Ref* Ref::autorelease(){ PoolManager::getInstance()->getCurrentPool()->addobject(this); // 交给自动释放池管理 return this;} unsigned int Ref::getReferenceCount() const{ return _referenceCount;}
总结一下,Ref类就做了几件事:
1、Ref自己不能实例化,只能由子类实例化;
2、创建是引用计数为1;
3、调用retain引用计数加1;
4、调用release引用计数减1;
5、调用autorelease并没有使引用计数减1,而是交给自动释放池来管理。
那么自动释放池是什么呢?肯定跟autorelease方法里面的PoolManager有关。
打开CCautoreleasePool.h文件查看,发现有两个类,一个是autoreleasePool,一个是PoolManager,从字面意思看,autoreleasePool就是自动释放池,而PoolManager就是池管理器,这些思路有点清晰了:
1、调用autorelease后对象交给autoreleasePool来管理;
2、PoolManager是用来管理autoreleasePool的,说明可以有多个池。
二、autoreleasePool
接下来一步步看,先看autoreleasePool自动释放池,看简化版本的:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // autoreleasePool.h class CC_DLL autoreleasePool { public : autoreleasePool(); // 疑问1:不要在堆上创建,而应该在栈上创建(为什么呢?等下解释) ~autoreleasePool(); voID addobject(Ref *object); // 添加一个Ref对象到释放池 clear(); // 清理自动释放池 private : std::vector<ref*> _managedobjectArray; // 用来保存这个自动释放池里面加入的所有Ref对象 };</ref*> |
// autoreleasePool.cpp autoreleasePool::autoreleasePool() { _managedobjectArray.reserve( 150 ); // 1、设置容器大小为150 PoolManager::getInstance()->push( this // 2、新建一个释放池时就加入了释放池管理器中(可以暂时放着,等看了PoolManager再回来看) } autoreleasePool::~autoreleasePool() { clear(); // 1、清理释放池 PoolManager::getInstance()->pop(); // 2、将释放池从释放池管理器中删除 } autoreleasePool::addobject(Ref* object) { _managedobjectArray.push_back(object); // 添加一个Ref对象到释放池中 } autoreleasePool::clear() { for ( const auto &obj : _managedobjectArray) // 1、调用所有自动释放对象的release函数,注意:只有当引用计数为0时才会delete对象,相同对象加入几次就会release几次 { obj->release(); } _managedobjectArray.clear(); // 2、清除容器 } |
1、维持一个保存Ref对象的队列,这些Ref对象调用autorelease就会加到该队列,调用addobject函数添加;
2、clear函数对autoreleasePool管理的所有Ref执行一次release *** 作,只有当引用计数为0时对象才会delete,加入几次就执行几次release *** 作。
三、PoolManager
PoolManager是管理释放池的,在autoreleasePool用到push和pop方法,可以猜到PoolManager应该维持一个存放释放池的栈:
?
// PoolManager.h CC_DLL PoolManager static PoolManager* getInstance(); // PoolManager是个单例模式 static voID destroyInstance(); // 删除单例模式创建的对象 autoreleasePool *getCurrentPool() ; // 获取当前的释放池 : PoolManager(); ~PoolManager(); push(autoreleasePool *pool); // 压入一个释放池 pop(); // d出一个释放池 PoolManager* s_singleInstance; std::deque _releasePoolStack; // 存放自动释放池的栈 autoreleasePool *_curReleasePool; // 当前的自动释放池 };</autoreleasepool*> |
// PoolManager.cpp PoolManager* PoolManager::s_singleInstance = nullptr; // 获取单例模式时,如果还没创建,则会创建两个释放池并添加到池管理器中 PoolManager* PoolManager::getInstance() { if (s_singleInstance == nullptr) { s_singleInstance = new PoolManager(); // 第一个池:autoreleasePool构造函数会将构造的池添加到池管理器中 s_singleInstance->_curReleasePool = autoreleasePool(); // 第二个池:将new出来的释放池再一次压入池管理器中 s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool); } return s_singleInstance; } // delete单例模式创建的对象 PoolManager::destroyInstance() delete s_singleInstance; s_singleInstance = nullptr; } PoolManager::PoolManager() { } // 析构函数 PoolManager::~PoolManager() { while (!_releasePoolStack.empty()) { autoreleasePool* pool = _releasePoolStack.back(); _releasePoolStack.pop_back(); // 1、d出自动释放池 delete pool; // 2、delete自动释放池对象 } } // 获取当前释放池 autoreleasePool* PoolManager::getCurrentPool() const { _curReleasePool; } PoolManager::push(autoreleasePool *pool) { @H_301_745@ _releasePoolStack.push_back(pool); // 1、压入释放池 _curReleasePool = pool; // 2、设为当前释放池 } // d出栈顶释放池,并将当前释放池指向新的栈顶释放池 PoolManager::pop() { CC_ASSERT(_releasePoolStack.size() >= 1 ); _releasePoolStack.pop_back(); (_releasePoolStack.size() > ) { _curReleasePool = _releasePoolStack.back(); } 貌似PoolManager功能更加简单,就是管理释放池。 |
评论列表(0条)