一、引用计数

基类Ref的作用就是通过引用计数来管理对象的生命周期,引用计数规则:

  • 引用计数
    • _referenceCount,初始为1。
  • retain()
    • _referenceCount加1。
  • release()
    • _referenceCount减1,如果此时为0了,删除对象。

cocos几乎所有对象都继承自Ref。
下面是Ref中引用计数相关的源码。

  1. class CC_DLL Ref
  2. {
  3. public:
  4. void retain(); // _referenceCount + 1
  5. void release(); // _referenceCount - 1
  6. Ref* autorelease(); // 加入当前的autoReleasePool
  7. unsigned int getReferenceCount() const; // 当前的引用计数
  8. protected:
  9. Ref(); // _referenceCount初始为1
  10. protected:
  11. unsigned int _referenceCount; // 当前这个对象的引用计数
  12. ......
  13. };
  14. Ref::Ref()
  15. : _referenceCount(1){
  16. }
  17. void Ref::retain(){
  18. ++_referenceCount;
  19. }
  20. void Ref::release(){
  21. --_referenceCount;
  22. if (_referenceCount == 0)
  23. {
  24. delete this;
  25. }
  26. }
  27. unsigned int Ref::getReferenceCount() const{
  28. return _referenceCount;
  29. }
  30. Ref* Ref::autorelease() //加入到当前的Pool中,见下面
  31. {
  32. PoolManager::getInstance()->getCurrentPool()->addObject(this);
  33. return this;
  34. }

二、自动化管理

我们已经能够管理cocos对象的生命周期,但是很麻烦,必须手动retain、release,我们可以借助渲染循环作为作为“驱动力”,来实现自动化。
cocos用一个AutoReleasePool来管理需要auto relase的Ref对象,用一个栈结构来保存pool,在帧结尾处,当前pool(栈顶pool)的所有对象release一次。

  1. void Director::mainLoop()
  2. {
  3. ......;
  4. drawScene();
  5. ......
  6. PoolManager::getInstance()->getCurrentPool()->clear(); // release the objects
  7. ......
  8. }

使用方法示例如下:

  1. void fuck()
  2. {
  3. // 在构造时候,poolManager将pool压栈 即成为current pool
  4. // pool在析构时,pool中所有Ref对象都将release一次,并弹栈
  5. AutoReleasePool pool;
  6. Node *pNode1 = Node::create(); // 加入current pool
  7. Node *pNode2 = Node::create(); // 加入current pool
  8. Ref *pRef = new Ref();
  9. pRef->autorelease(); // 加入current pool
  10. Director::getInstnace()->getRunningScene()->addChild(pNode1);
  11. }
  12. // 函数结束,触发pool的析构,上面所有Ref对象都release一次,
  13. // release之后,引用计数情况如下:
  14. // pNode1->release之后,引用计数=1,当runningScene->removeChild(pNode1)时,pNode1将被delete
  15. // pNode2->release之后,引用计数=0,立即被delete
  16. // pRef->release之后,引用计数=0,立即被delete

相关源码如下:

AutoreleasePool

自动回收池,存储要进行AutoRelease的Ref对象。

  1. std::vector<Ref*> _managedObjectArray; // 存储要autoRelease的对象
  2. AutoreleasePool::AutoreleasePool(){
  3. // 预计管理的对象数量不会超过150个。
  4. _managedObjectArray.reserve(150);
  5. PoolManager::getInstance()->push(this); //设置为当前的AutoreleasePool
  6. }
  7. AutoreleasePool::~AutoreleasePool(){ //清空池,所有对象release
  8. clear();
  9. PoolManager::getInstance()->pop(); //当前AutoreleasePool改为上一个
  10. }
  11. void AutoreleasePool::addObject(Ref* object){ //对象加入AutoreleasePool
  12. _managedObjectArray.push_back(object);
  13. }
  14. void AutoreleasePool::clear(){ //清空池,所有对象release
  15. std::vector<Ref*> releasings;
  16. releasings.swap(_managedObjectArray);
  17. for (const auto &obj : releasings){
  18. obj->release();
  19. }
  20. }

PoolManager

通过一个栈来管理AutoreleasePool,需要自动回收的对象都将被添加到栈顶的Pool中,即当前的Pool。
栈底初始有一个常驻的Pool。
部分源码如下:

  1. // 栈结构,保存auto release pool,栈顶pool为当前pool
  2. std::vector<AutoreleasePool*> _releasePoolStack;
  3. PoolManager* PoolManager::getInstance(){
  4. if (s_singleInstance == nullptr){
  5. s_singleInstance = new (std::nothrow) PoolManager();
  6. new AutoreleasePool("cocos2d autorelease pool"); // 栈底初始就有一个Pool
  7. }
  8. return s_singleInstance;
  9. }
  10. PoolManager::PoolManager(){
  11. _releasePoolStack.reserve(10); // Pool最好限制在10个以内。
  12. }
  13. AutoreleasePool* PoolManager::getCurrentPool() const { // 栈顶Pool
  14. return _releasePoolStack.back();
  15. }
  16. void PoolManager::push(AutoreleasePool *pool){
  17. _releasePoolStack.push_back(pool);
  18. }
  19. void PoolManager::pop(){
  20. _releasePoolStack.pop_back();
  21. }