zoukankan      html  css  js  c++  java
  • 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,切记。

              
             
    void Ref::retain()
    {
        CCASSERT(_referenceCount > 0, "reference count should greater than 0");
        ++_referenceCount;
    }
    Ref* Ref::autorelease()
    {
        PoolManager::getInstance()->getCurrentPool()->addObject(this);
        return this;
    }
    void Ref::release()
    {
        CCASSERT(_referenceCount > 0, "reference count should greater than 0");
        --_referenceCount;
        if (_referenceCount == 0)
        {
            delete this;
        }
    }

              当中一些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 源代码分析

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

    AutoRealse的clear函数十分清晰,就是调用其包括的ref的release函数,然后将自己的managedObject清空。这里须要解决的疑惑是何时调用了clear函数。打开Director的源代码
    void DisplayLinkDirector::mainLoop()
    {
    
        if (_purgeDirectorInNextLoop)
        {
            _purgeDirectorInNextLoop = false;
            purgeDirector();
        }
        else if (! _invalid)
        {
            drawScene();
         
            // release the objects
            PoolManager::getInstance()->getCurrentPool()->clear();
        }
    }

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

    2.3 PoolManager

            std::deque<AutoreleasePool*> _releasePoolStack;
            AutoreleasePool *_curReleasePool;
            PoolManager管理着全部的autorerealsePool,而且有一个指针指向当前的releasePool。
            值得注意的是。笔者觉得3.x此处有个小bug。
            
    PoolManager* PoolManager::getInstance()
    {
        if (s_singleInstance == nullptr)
        {
            s_singleInstance = new PoolManager();
            // Add the first auto release pool
            s_singleInstance->_curReleasePool = new AutoreleasePool("cocos2d autorelease pool");
            s_singleInstance->_releasePoolStack.push_back(s_singleInstance->_curReleasePool);
        }
        return s_singleInstance;
    }


            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用途。

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    登录界面
    动手动脑
    关于二进制
    Java考试
    D
    威尔逊定理 k!%p
    11.46.2020质检
    最长上升序列输出方案
    问题 G: 汽车的最终位置
    奶牛大会(二分)
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4622614.html
Copyright © 2011-2022 走看看