cocos2d-x 源码分析 : Ref (CCObject) 源码分析 cocos2d-x内存管理策略

源码版本来自3.x,转载请注明

cocos2d-x 源码分析总目录:

http://blog.csdn.net/u011225840/article/details/31743129


1.Ref,AutoreleasePool,PoolManager

Ref中包含了一个叫referenceCount的引用计数,当一个Ref类的变量被new的时候,其referenceCount的引用计数被置为1。 其中有三个重要的操作,retain,release,autorelease,下面源码分析时会详细说明。
        AutoreleasePool中存放在被显示调用autorealse的ref,并且在每一帧过后调用其clear函数,显示的调用存放在其中的ref的realse函数,然后清空自身。
        PoolManager则管理着所欲的AutoreleasePool,没有错,不仅仅有一个AutoreleasePool,有多个AutoreleasePool。

2.源码分析

         如果你想清晰的了解cocos2d-x 3.x 的内存管理机制,请你一定要耐心阅读完这里的代码,源代码本身清晰易懂,何况我已经加了一些必要的中文注释呢~

2.1 Ref源码分析

          重要的成员变量:_referenceCount,在构造函数中被置为1,切记。
          
         
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ref::retain()  
  2. {  
  3.     CCASSERT(_referenceCount > 0, "reference count should greater than 0");  
  4.     ++_referenceCount;  
  5. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Ref* Ref::autorelease()  
  2. {  
  3.     PoolManager::getInstance()->getCurrentPool()->addObject(this);  
  4.     return this;  
  5. }  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ref::release()  
  2. {  
  3.     CCASSERT(_referenceCount > 0, "reference count should greater than 0");  
  4.     --_referenceCount;  
  5.     if (_referenceCount == 0)  
  6.     {  
  7.         delete this;  
  8.     }  
  9. }  

          其中一些Debug或者追踪memory leak 的宏和函数我已经去掉,其实这三个函数的本质就是这么简单,retain和release分别增加和减少referenceCount,并且release函数在count为0时就delete 自己。autorelease函数将Ref放入当前的AutorealsePool。
         Attention Please:三个函数内部都有一个CCASSERT,要求调用时该object的referenceCout必须是大于0的。
                                           release或者autorealse必须和new或者retain成对出现。

         这里开始讲一下基本的用法,因为我们平时需要我们管理的、使用的类一般都是继承于Node(Layer、Sprite等),看下Node的create函数吧。
         在Node的create中,调用了new(Count设置为1)后,立即调用了autoRelease,将其放入AutoreleasePool中。(AutoreleasePool的源码一会再分析)
         所以当你使用了create之后,请不要在使用release或者Autorelease,除非你手动了retain一次。
         但是当你把一个node1加入到另一个node2的时候,你可以理解为此时node1的refereneceCount增加了一次,但是你不需要做任何额外的操作。因为当node1被remove或者即使没有remove操作,当node2析构的时候(会将他的child的count减1)。也就是说,整个引擎会自动管理referenceCount,只要你不要手动的retain。


2.2AutoreleasePool 源码分析

         
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void AutoreleasePool::clear()  
  2. {  
  3. #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)  
  4.     _isClearing = true;  
  5. #endif  
  6.     for (const auto &obj : _managedObjectArray)  
  7.     {  
  8.         obj->release();  
  9.     }  
  10.     _managedObjectArray.clear();  
  11. #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)  
  12.     _isClearing = false;  
  13. #endif  
  14. }  

AutoRealse的clear函数十分清晰,就是调用其包含的ref的release函数,然后将自己的managedObject清空。这里需要解决的疑惑是何时调用了clear函数。打开Director的源码
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void DisplayLinkDirector::mainLoop()  
  2. {  
  3.   
  4.     if (_purgeDirectorInNextLoop)  
  5.     {  
  6.         _purgeDirectorInNextLoop = false;  
  7.         purgeDirector();  
  8.     }  
  9.     else if (! _invalid)  
  10.     {  
  11.         drawScene();  
  12.        
  13.         // release the objects  
  14.         PoolManager::getInstance()->getCurrentPool()->clear();  
  15.     }  
  16. }  

在你的App运行时,每一帧开始时都是先drawScene(),各种界面上的显示结束后,就开始clear了。

2.3 PoolManager

        std::deque<AutoreleasePool*> _releasePoolStack;
        AutoreleasePool *_curReleasePool;
        PoolManager管理着所有的autorerealsePool,并且有一个指针指向当前的releasePool。
        值得注意的是,笔者认为3.x此处有个小bug。
        
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. PoolManager* PoolManager::getInstance()  
  2. {  
  3.     if (s_singleInstance == nullptr)  
  4.     {  
  5.         s_singleInstance = new PoolManager();  
  6.         // Add the first auto release pool  
  7.         s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool");  
  8.         s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool);  
  9.     }  
  10.     return s_singleInstance;  
  11. }  


        poolManager是单例模式,当第一次初始化的时候,会自动生成一个AutoreleasePool,并将其放入自己的stack中。但是,当你打开AutoreleasePool的构造函数时,发现其中已经有一个调用PoolManager::getInstance()->push(this); 通过debug跟踪,笔者发现此时有两个AutoRealsePool。即poolManager的stack内有两个位置都指向同一个AutoRealsePool。感觉此处应该是一个Bug。


3. 小结

        1.Ref,AutorealsePool,PoolManager是紧密相关的
        2.Ref的retain、new  应该与 release或者autoRealse成对出现。
        3.Node的使用方式。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值