首页 > 代码库 > 浅谈自己对cocos2dx的内存管理的理解

浅谈自己对cocos2dx的内存管理的理解

拿个自己写Layer的例子

1         auto genMenuWnd = GeneralMenuWnd::create();
2         CC_BREAK_IF(!genMenuWnd);
3         addChild(genMenuWnd, 100);

该引用计数变化流程

GeneralMenuWnd在create()的时候,其_referenceCount 为1,并在create()的时候autorelease();

addChild()的时候,其_referenceCount变为2;

当该帧执行完后,_referenceCount变为1;

genMenuWnd析构时,_referenceCount变为0, 删除;

大体是这样子的:

GeneralMenuWnd继承Ref,Ref的构造函数:

 1 Ref::Ref()
 2 : _referenceCount(1) // when the Ref is created, the reference count of it is 1 其引用计数默认为1
 3 #if CC_ENABLE_SCRIPT_BINDING
 4 , _luaID (0)
 5 , _scriptObject(nullptr)
 6 , _rooted(false)
 7 , _scriptOwned(false)
 8 ,_referenceCountAtRootTime(0)
 9 #endif
10 {
11 #if CC_ENABLE_SCRIPT_BINDING
12     static unsigned int uObjectCount = 0;
13     _ID = ++uObjectCount;
14 #endif
15     
16 #if CC_REF_LEAK_DETECTION
17     trackRef(this);
18 #endif
19 }

在GeneralMenuWnd::create()中会调用autorelease(); 此时genMenuWnd会被放在AutoreleasePool里面.

1 Ref* Ref::autorelease()
2 {
3     PoolManager::getInstance()->getCurrentPool()->addObject(this);
4     return this;
5 }

 

执行addChild(), 流程addChild() --->  addChildHelper() ---> insertChild()

 1 void Node::addChild(Node* child, int localZOrder, const std::string &name)
 2 {
 3     CCASSERT(child != nullptr, "Argument must be non-nil");
 4     CCASSERT(child->_parent == nullptr, "child already added. It can‘t be added again");
 5     
 6     addChildHelper(child, localZOrder, INVALID_TAG, name, false); //第一步
 7 }
 8 
 9 void Node::addChildHelper(Node* child, int localZOrder, int tag, const std::string &name, bool setTag)
10 {
11     if (_children.empty())
12     {
13         this->childrenAlloc();
14     }
15     
16     this->insertChild(child, localZOrder); //第二步
17     
18     if (setTag)
19         child->setTag(tag);
20     else
21         child->setName(name);
22     
23     child->setParent(this);
24     child->setOrderOfArrival(s_globalOrderOfArrival++);
25     
26     if( _running )
27     {
28         child->onEnter();
29         // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
30         if (_isTransitionFinished)
31         {
32             child->onEnterTransitionDidFinish();
33         }
34     }
35     
36     if (_cascadeColorEnabled)
37     {
38         updateCascadeColor();
39     }
40     
41     if (_cascadeOpacityEnabled)
42     {
43         updateCascadeOpacity();
44     }
45 }

 

1 // helper used by reorderChild & add
2 void Node::insertChild(Node* child, int z) 3 {
4     _transformUpdated = true;
5     _reorderChildDirty = true;
6     _children.pushBack(child); //第三步
7     child->_localZOrder = z;
8 }

 _children是一个Vector容器(cocos2dx自己封装过的)它在pushBack的时候是这个样子

1  void pushBack(T object)
2     {
3         CCASSERT(object != nullptr, "The object should not be nullptr");
4         _data.push_back( object );
5         object->retain();  //在这里, 引用计数被加1
6     }

 执行完addChild()之后,其引用计数为2

在当前帧执行完成时:

 1 void DisplayLinkDirector::mainLoop()
 2 {
 3     if (_purgeDirectorInNextLoop)
 4     {
 5         _purgeDirectorInNextLoop = false;
 6         purgeDirector();
 7     }
 8     else if (_restartDirectorInNextLoop)
 9     {
10         _restartDirectorInNextLoop = false;
11         restartDirector();
12     }
13     else if (! _invalid)
14     {
15         drawScene();
16      
17         // release the objects
18         PoolManager::getInstance()->getCurrentPool()->clear();//在这里会清空自动释放池中的所有单位,即其引用计数-1
19     }
20 }

 所以这个时候其引用计数为1。

在genMenuWnd析构的时候,会释放_children,此时调用Vector()的clear()

1  void clear()
2     {
3         for( auto it = std::begin(_data); it != std::end(_data); ++it ) {
4             (*it)->release();
5         }
6         _data.clear();
7     }

 

所以该节点的引用计数变为了0,此时会进行delete

 

浅谈自己对cocos2dx的内存管理的理解