<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Cocos內存管理解析 CCRef/retain/release/autorelease

      Cocos內存管理源碼(autorelease解析)

      背景

      這段時間在做項目的時候,需求需要往spine動作的掛點上綁定按鈕節點,由于按鈕在編輯器中是加在已有節點上的,所以在往spine上添加掛點時,需要先移除按鈕,然后再綁定的掛點上。

      local spineAnim = sp.SkeltonAnimation:create(skeletonFile, atlasFile, 1.0, true)
      local btnGame = roleNode:getChildByName("btnGame")
      btnGame:removeFromParent()
      spineAnim:addSlotBindInfo("qianwangduiju", btnGame, Defind.slotBindType.slotBindType_all)
      

      如果直接這樣寫,會在某種情況導致btnGame按鈕節點丟失,無法正常掛載再spine動畫節點上,后續優化了此方案

      local spineAnim = sp.SkeltonAnimation:create(skeletonFile, atlasFile, 1.0, true)
      local btnGame = roleNode:getChildByName("btnGame")
      btnGame:retain()
      btnGame:removeFromParent()
      btnGame:autorelease()
      spineAnim:addSlotBindInfo("qianwangduiju", btnGame, Defind.slotBindType.slotBindType_all)
      

      在移除按鈕之前,先retain一下,這樣引用計數加1,就不會導致內存被回收,再調用autorelease,此時并不會release對象,這時會將此節點加入_managedObjectArry對象池中,在Director的mainLoop中會調用PoolManager::getInstance()->getCurrentPool()->clear();

      具體詳情解析,請接著看

      cocos2dx-3.8中的自動內存管理是用引用計數來實現的,對于老版本的coocs引用計數使用的是CCObejct,但這個類后續被棄用了,使用CCRef代替,cocos中幾乎所有的類都是繼承于CCRef

      CCRef基本原理就是其內部存在一個引用計數_referenceCount,當這個計數為0時,就會被釋放。引用計數通過retain,release操作。

      Ref從創建到銷毀的過程

      舉個栗子,向屏幕中添加一個Button來測試Ref的創建和銷毀,首先創建一個Button

      auto button = Button::create();
      button->setName("myButton");
      addChild(button);
      

      以上代碼就是向屏幕中添加一個button,讓我們看看create做了什么

      Button* Button::create()
      {
          Button* widget = new (std::nothrow) Button();
          if (widget && widget->init())
          {
              widget->autorelease();
              return widget;
          }
          CC_SAFE_DELETE(widget);
          return nullptr;
      }  
      

      create函數是一個工廠方法,cocos中很多類都實現了這個方法,其中可以看到ret->autorelease();,這個函數就是把當前對象加入到自動釋放池內,對于自動釋放池下面會詳細講解。(注:Ref初始化的時候引用計數為1不是0

      接下來看下addChild()接口,此處截取了一部分

      void Node::addChild(Node *child){
          CCASSERT( child != nullptr, "Argument must be non-nil");
          this->addChild(child, child->_localZOrder, child->_name);
      }
      
      void Node::addChild(Node* child, int localZOrder, const std::string &name){
          ...
          addChildHelper(child, localZOrder, INVALID_TAG, name, false);
      }
      
      void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag){
          ...
          this->insertChild(child, localZOrder);
          ...
      }
      
      void Node::insertChild(Node* child, int z){
          _transformUpdated = true;
          _reorderChildDirty = true;
          _children.pushBack(child);
          child->_localZOrder = z;
      }
      

      最終跳轉到insertChild中,通過 _children.pushBackbutton加入到_children中去,到底引用計數在哪里+1操作?答案在pushBack操作中,_childrencocosRef量身定制的向量Vector<T>,這個向量只能給繼承Ref的類使用

      void pushBack(T object){
          ...
          _data.push_back( object );
          object->retain();
      }
      

      代碼中可以看到object->retain(),對添加進來的對象引用+1操作,那么什么時候-1呢?

      當我們移除場景的時候,應該釋放場景中的button的。Node被移除時會調用當前的Node的父親的removeChild函數,此函數最后會調用Nodecleanup函數,cleanup函數時遞歸函數,會遍歷所有子節點。當cleanup完之后會從父節點的_children這個向量中刪除,此時就會調用release函數

      //當某個兒子節點cleanup完之后會調用_children.earse(childIndex)
      iterator erase(ssize_t index){
          ...
          auto it = std::next( begin(), index );
          (*it)->release();
          return _data.erase(it);
      }
      

      release函數就是當前實例的引用計數-1,如果-1后為0那么釋放內存

      void Ref::release(){
          ...
          --_referenceCount;
      
          if (_referenceCount == 0){
              ...
              delete this;
          }
      }
      

      自動釋放池

      Ref中的autorelease函數,咋一看感覺內存不需要我來管了,他會自動釋放。然而這個自動和我腦子里面的自動向差一個孫猴子的跟頭,畢竟c++不是java,先看看autorelease的源碼

      Ref* Ref::autorelease()
      {
      	PoolManager::getInstance()->getCurrentPool()->addObject(this);
          return this;
      }
      

      代碼很短,autorelease并沒有release,而是把對象加入到了對象池中。那么這個對象池是什么時候去release里面的對象呢?接下來就要看DirectormainLoop函數了,這個函數在Director中實現。

      void Director::mainLoop()
      {
          if(_purgeDirectorInNextLoop)
          {
              ...
          }
          else if(_restartDirectorInNextLoop)
          {
              ...
          }
          else if(!_invalid)
          {
              drawScene();
              
              // release the objects
              PoolManager::getInstance()->getCurrentPool()->clear();
          }
      }
      

      mainLoop是每一幀調用的函數,我們發現cocos在每一幀結束繪制drawScene之后都會調用PoolManager::getInstance()->getCurrentPool()->clear();的操作,接下來我們看看clear的實現細節。

      void AutoreleasePool::clear()
      {
      #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
          _isClearing = true;
      #endif
          std::vector<Ref*> releasings;
          releasings.swap(_managedObjectArray);
          for (const auto &obj : releasings)
          {
              obj->release();
          }
      #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
          _isClearing = false;
      #endif
      }
      

      我們發現,在clear里面對所有在_managedObjectArray中的所有對象都進行一次release操作,并把它從_managedObjectArray中刪掉。_managedObjectArray是什么,查看前一段代碼中addObject的實現細節就知道,autorelease就是把當前對象加入到_managedObjectArray

      也就是說,我們創建的Button的時候引用計數為1,然后調用autorelease添加到_managedObjectArray中,之后又被addChild到屏幕中,此時引用計數為2。當一幀繪制結束的時候會系統會調用釋放池的clear函數,此函數會遍歷所有在自動釋放池內的對象并release,最后從對象池中刪除之(所以第二幀結束后不會被再次調用release了),此時引用計數為1。當我們把當前場景移除的時候會調用release把引用計數減少至0,并從內存中釋放。

      posted @ 2021-07-23 15:55  Mike丶  閱讀(343)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲一区二区三区啪啪| 巨胸喷奶水视频www免费网站| 东阿县| 亚洲码亚洲码天堂码三区| 亚洲欧美综合精品成人网站| 亚洲精品成人福利网站| 狠狠v日韩v欧美v| 欧美大胆老熟妇乱子伦视频 | 国产综合色产在线视频欧美| 人妻少妇乱子伦精品无码专区电影 | 久久综合精品成人一本| 国产成人午夜精品影院| 国产熟妇久久777777| 欧美高清狂热视频60一70| 国产精品无码av在线一区 | 国产一区二区一卡二卡| 午夜亚洲国产理论片亚洲2020| 在线精品国产中文字幕| japanese边做边乳喷| 偷拍专区一区二区三区| 视频区 国产 图片区 小说区| 亚洲激情av一区二区三区| 加勒比无码人妻东京热| 国产精品自在自线视频| 少妇高潮尖叫黑人激情在线| 成人区人妻精品一区二蜜臀| 9丨精品国产高清自在线看| 国产成人精品视频不卡| 最近中文字幕免费手机版| 日韩人妻精品中文字幕| 人人色在线视频播放| 奶头好大揉着好爽视频| 四虎永久免费精品视频| 日本高清在线播放一区二区三区 | 91国在线啪精品一区| 华人在线亚洲欧美精品| 精品熟女少妇av免费久久| 亚洲熟妇自偷自拍另欧美 | 久久人人97超碰人人澡爱香蕉| 日本久久一区二区免高清| 尹人香蕉久久99天天拍欧美p7 |