美文网首页
cocos2dx内存管理

cocos2dx内存管理

作者: 咸鱼而已 | 来源:发表于2017-10-12 09:31 被阅读123次

cocos2dx内存管理是基于引用计数的,有一个Ref类专门用来管理引用计数,所有的cocos2dx对象都是派生自Ref类,从这个类派生的cocos2dx对象可以自动进行内存管理。引用计数为0,就会被释放

1.cocos2dx对象初始化的流程:

auto sp = Sprite::create("CloseNormal.png");最终会调用Ref的构造函数

Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1
#if CC_ENABLE_SCRIPT_BINDING
, _luaID (0)
, _scriptObject(nullptr)
, _rooted(false)
, _scriptOwned(false)
,_referenceCountAtRootTime(0)
#endif
{
#if CC_ENABLE_SCRIPT_BINDING
    static unsigned int uObjectCount = 0;
    _ID = ++uObjectCount;
#endif
    
#if CC_REF_LEAK_DETECTION
    trackRef(this);
#endif
}

创建的时候,会把_referenceCount置为1。然后看一下Sprite的构造函数:

Sprite* Sprite::create(const std::string& filename)
{
    Sprite *sprite = new (std::nothrow) Sprite();
    if (sprite && sprite->initWithFile(filename))
    {
        sprite->autorelease();
        return sprite;
    }
    CC_SAFE_DELETE(sprite);
    return nullptr;
}

可以看到autorelease方法,把Sprite加到AutoreleasePool中。然后再Director的mainLoop()方法中会调用AutoreleasePool的clear()方法。因为mainLoop是每帧调用一次,然后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
}

这里会调用obj->release()方法,会使引用计数-1,如果引用计数为0,会释放这个对象。
到此为止,一个对象创建出来的内存管理流程已经差不多了。

2.添加子节点

rootNode->addChild(sp);方法是把我们创建出来的cocos2dx对象添加到UI树上,看一下addChild的实现:

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)
{
    if (_children.empty())
    {
        this->childrenAlloc();
    }
    this->insertChild(child, localZOrder);
    if (setTag)
        child->setTag(tag);
    else
        child->setName(name);

    child->setParent(this);
    child->setOrderOfArrival(s_globalOrderOfArrival++);
    
    if( _running )
    {
        child->onEnter();
        // prevent onEnterTransitionDidFinish to be called twice when a node is added in onEnter
        if (_isTransitionFinished)
        {
            child->onEnterTransitionDidFinish();
        }
    }
    
    if (_cascadeColorEnabled)
    {
        updateCascadeColor();
    }
    
    if (_cascadeOpacityEnabled)
    {
        updateCascadeOpacity();
    }
}

addChild()方法内部会调用addChildHelper(),然后重点看一下this->insertChild(child, localZOrder);`这个方法:

// helper used by reorderChild & add
void Node::insertChild(Node* child, int z)
{
    _transformUpdated = true;
    _reorderChildDirty = true;
    _children.pushBack(child);
    child->_localZOrder = z;
}

这里会调用_children.pushBack(child);这个方法,这里的_children是cocos2dx实现的一个Vector,专门用来存储cocos2dx对象,看一下pushBack的实现:

void pushBack(T object)
{
    CCASSERT(object != nullptr, "The object should not be nullptr");
    _data.push_back( object );
    object->retain();
}

这里有一个retain操作会对引用计数+1,这样添加节点的时候引用计数就会+1就很明朗了。

3.删除子节点

先看看void Node::removeChild(Node* child, bool cleanup /* = true */)方法:

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 );
}

注意一下detachChild这个方法:

void Node::detachChild(Node *child, ssize_t childIndex, bool doCleanup)
{
    // IMPORTANT:
    //  -1st do onExit
    //  -2nd cleanup
    if (_running)
    {
        child->onExitTransitionDidStart();
        child->onExit();
    }

    // If you don't do cleanup, the child's actions will not get removed and the
    // its scheduledSelectors_ dict will not get released!
    if (doCleanup)
    {
        child->cleanup();
    }

    // set parent nil at the end
    child->setParent(nullptr);

    _children.erase(childIndex);
}

这里注意一下_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();
    return _data.erase(it);
}

这里会调用release()方法,引用计数—1。到这里,已经完成了,内存管理。

然后看一下child->cleanup():

void Node::cleanup()
{
#if CC_ENABLE_SCRIPT_BINDING
    if (_scriptType == kScriptTypeJavascript)
    {
        if (ScriptEngineManager::sendNodeEventToJS(this, kNodeOnCleanup))
            return;
    }
    else if (_scriptType == kScriptTypeLua)
    {
        ScriptEngineManager::sendNodeEventToLua(this, kNodeOnCleanup);
    }
#endif // #if CC_ENABLE_SCRIPT_BINDING
    
    // actions
    this->stopAllActions();
    this->unscheduleAllCallbacks();

    // timers
    for( const auto &child: _children)
        child->cleanup();
}

主要是一些清理工作,停止动作,取消回调。并对子节点做一个cleanup操作

相关文章

  • Cocos2dx笔记(3.x)

    1. 内存管理 Cocos2dx是通过引用计数方式管理内存,主要通过两种方式实现。 1.1 手动内存管理 手动re...

  • cocos2dx内存管理

    cocos2dx内存管理是基于引用计数的,有一个Ref类专门用来管理引用计数,所有的cocos2dx对象都是派生自...

  • 学习cocos2dx的内存管理

    最近经常要查阅cocos2dx的源码,看下scrollview、button控件的实现,看看触摸事件处理等等,发现...

  • iOS内存管理详解

    目录 block内存管理 autorelease内存管理 weak对象内存管理 NSString内存管理 new、...

  • 第10章 内存管理和文件操作

    1 内存管理 1.1 内存管理基础 标准内存管理函数堆管理函数虚拟内存管理函数内存映射文件函数 GlobalMem...

  • 操作系统之内存管理

    内存管理 包括内存管理和虚拟内存管理 内存管理包括内存管理概念、交换与覆盖、连续分配管理方式和非连续分配管理方式(...

  • JavaScript —— 内存管理及垃圾回收

    目录 JavaScript内存管理内存为什么需要管理?内存管理概念JavaScript中的内存管理JavaScri...

  • OC - OC的内存管理机制

    导读 一、为什么要进行内存管理 二、内存管理机制 三、内存管理原则 四、MRC手动内存管理 五、ARC自动内存管理...

  • 3. 内存管理

    内存管理 内存管理包含: 物理内存管理; 虚拟内存管理; 两者的映射 除了内存管理模块, 其他都使用虚拟地址(包括...

  • Cocos2dx lua Xcode Mac

    Cocos2dx lua Xcode Mac 1. 下载Cocos2dx 相关文件 2. 新建Cocos2dX l...

网友评论

      本文标题:cocos2dx内存管理

      本文链接:https://www.haomeiwen.com/subject/kblnyxtx.html