cocos2d-x 3.6版本学习笔记-内存管理之Node对象
来源:互联网 发布:环球捕手 知乎 编辑:程序博客网 时间:2024/06/10 16:52
由于C++目前未提供完整的垃圾回收机制,cocos2d-x必须手动来管理内存。3.6版本里,cocos2d-x使用了一种类oc的内存管理机制,利用引用计算来控制对象的释放。
在cocos2d-x中,几乎所有的对象都继承自Ref类,而各对象的引用计数也都在Ref类中维护,Ref类结构如下(代码1):
class CC_DLL Ref{public: void retain(); void release(); Ref* autorelease(); unsigned int getReferenceCount() const;protected: unsigned int _referenceCount; friend class AutoreleasePool; ...};对象每retain一次引用计数加1,每release一次引用计数减1,当引用计算减到0时,释放资源。
我们可以手动retain,release控制对象的引用计数,也可以通过autorelease来自动化管理对象引用计数。
所谓的自动化管理,就是调用create方法创建Ref对象后,无需手动调用release方法,系统在适当的时候自动调用release方法,这种方便主要是针对 node类型的对象。
以Sprite为例,首先创建一个Sprite对象,create函数实现如下(代码2):
Sprite* Sprite::create(const std::string& filename){ Sprite *sprite = new (std::nothrow) Sprite();//所有Ref对象引用计数,初始值为1 if (sprite && sprite->initWithFile(filename)) { sprite->autorelease(); return sprite; } CC_SAFE_DELETE(sprite); return nullptr;}成功的话,返回一个autorelease对象,autorelease函数实现如下(代码3):
Ref* Ref::autorelease(){ PoolManager::getInstance()->getCurrentPool()->addObject(this); return this;}
void AutoreleasePool::addObject(Ref* object){ _managedObjectArray.push_back(object);}autorelease只是将对象添加到一个全局的对象池中。其中_managedObjectArray是一个std::vector<Ref*>类型的容器(注,是标准库的容器,非cocos容器)。
至此,对象创建完成。
第二步,将sprite添加到helloworld场景当中。代码如下(代码4):
bool HelloWorld::init(){ ... this->addChild(sprite, 0); return true;}
void Node::addChild(Node *child, int zOrder){ CCASSERT( child != nullptr, "Argument must be non-nil"); this->addChild(child, zOrder, child->_name);}
void Node::addChild(Node* child, int localZOrder, const std::string &name){ CCASSERT(child != nullptr, "Argument must be non-nil"); CCASSERT(child->_parent == nullptr, "child already added. It can't be added again"); 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);//注:这里的_children窗口为cocos2d::Vector<Node*>类型,非std::Vector child->_localZOrder = z;}
void pushBack(T object) { CCASSERT(object != nullptr, "The object should not be nullptr"); _data.push_back( object ); object->retain();//引用计数为2 }可以看到,在sprite添加到父节点时,子结点会有一次retain()的操作,retain()完后引用计数为2。
在一帧绘制完毕后,director将会对对象池里的对象进行一次release,代码如下(代码5):
void DisplayLinkDirector::mainLoop(){ ... drawScene();//sprite引用计数为2 PoolManager::getInstance()->getCurrentPool()->clear();//sprite引用计数为1 ...}clear函数中,将对对象池中的所有对象引用计算减1。
可以看到,上述过程中,sprite对象引用计数一直大于0,所以一直未销毁(程序的逻辑上确实也是如此)。
那么问题来了,sprite什么时候销毁呢?当引用计数减到0的时候(这是废话),有几种情况会使的sprite的引用计数减1:
1)场景销毁的时候_runningScene->release();
2)场景重新运行的时候
3)sprite从父节点remove掉的时候
前2种情况是对所有的对象池里的数据进行引用减1,第3种是对特定的remove对象引用减1。代码如下(代码6):
void Node::removeChild(Node* child, bool cleanup /* = true */){ // explicit nil handling if (_children.empty()) { return; } ssize_t index = _children.getIndex(child); if( index != CC_INVALID_INDEX ) this->detachChild( child, index, cleanup );}void Node::detachChild(Node *child, ssize_t childIndex, bool doCleanup){ ... // set parent nil at the end child->setParent(nullptr); _children.erase(childIndex);}iterator erase(ssize_t index) { CCASSERT(!_data.empty() && index >=0 && index < size(), "Invalid index!"); auto it = std::next( begin(), index ); (*it)->release();//减1操作在此! return _data.erase(it); }当对象引用计数为0的时候,对象会释放自身的资源,并且会删除对象池里的引用(如果存在的话)。
总结一下:cocos的autorelease(自动释放)机制,即:
对于node的子类,将new与delete操作与create(),addchild(),removechild()等操作绑定。 当对象从UI上移除也表示着其资源得到释放。
- cocos2d-x 3.6版本学习笔记-内存管理之Node对象
- cocos2d-x 3.6版本学习笔记-内存管理之智能指针
- 【cocos2d-x 3.x 学习笔记】对象内存管理
- cocos2d-x学习笔记内存管理之autorelease
- cocos2d-x学习笔记内存管理之autorelease
- cocos2d-x学习笔记内存管理之autorelease
- cocos2d-x学习笔记内存管理之autorelease
- Cocos2d-X 学习笔记 19 cocos2d-x学习之自动内存管理和常见宏
- cocos2d-x学习笔记:内存管理
- Cocos2d-x 3.6版本学习笔记-热更新
- cocos2d-x 3.6版本学习笔记-渲染过程
- cocos2d-x学习笔记18:内存管理01:概述
- cocos2d-x学习笔记18:内存管理01:概述
- cocos2d-x学习笔记——内存管理
- 我的Cocos2d-x学习笔记(十二)内存管理
- Cocos2d-x学习笔记(四)—— 内存管理
- cocos2d-x学习之自动内存管理和常见宏
- cocos2d-x学习之自动内存管理和常见宏
- MFC CTooLBar 工具栏显示提示信息ToolTip
- Android Fragment制作Tab
- Gradle入门系列(1):简介
- 学习技巧:读原版小说提升外语水平
- hdu 2082 找单词(母函数)
- cocos2d-x 3.6版本学习笔记-内存管理之Node对象
- 程序员有趣的面试智力题
- GRE双满分经验分享 我的5个月学习计划
- Android 圆形ImageView
- window.status无法获取
- Linux的vim三种模式及命令
- Gradle入门系列(2):第一个Java项目
- 【Discuz】导航条、搜索栏的修改
- samba 共享配置