zoukankan      html  css  js  c++  java
  • 从零开始のcocos2dx生活(一)内存管理

    cocos中所有的对象都是继承自Ref基类,Ref的职责就是对对象进行引用计数管理

    内存管理中最重要的是三个方法retain()、release()、autorelease()

    在cocos中创建对象的标准流程是:
    创建对象->初始化->添加到自动内存管理->返回创建成功的对象
    就比如下面这段代码1:创建Node对象

    //代码1
    Node * Node::create()
    {
        Node * ret = new (std::nothrow) Node();
        if (ret && ret->init())
        {
            ret->autorelease();
        }
        else
        {
            CC_SAFE_DELETE(ret);
        }
        return ret;
    }
    

    在代码1中,我们只需要调用create方法就可以实现创建对象、初始化和自动管理内存。

    在cocos中有的函数中直接使用了create的宏定义,调用对象的create方法就可以执行代码2,实现的功能和代码1是一样的。

    //代码2
    #define CREATE_FUNC(__TYPE__) \
    static __TYPE__* create() \
    { \
        __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
        if (pRet && pRet->init()) \
        { \
            pRet->autorelease(); \
            return pRet; \
        } \
        else \
        { \
            delete pRet; \
            pRet = nullptr; \
            return nullptr; \
        } \
    }
    

    代码2中调用autorelease方法,将对象加入自动内存管理池自动管理。
    代码3是autorelease方法的实现

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

    首先看一下代码4,PoolManager的getInstance方法
    在代码4中创建了PoolManager对象并调用了this的AutoreleasePool方法(代码5)
    "cocos2d autorelease pool"是这个自动管理池的name

    //代码4
    PoolManager* PoolManager::getInstance()
    {
        if (s_singleInstance == nullptr)
        {
            s_singleInstance = new (std::nothrow) PoolManager();
            // Add the first auto release pool
            new AutoreleasePool("cocos2d autorelease pool");
        }
        return s_singleInstance;
    }
    

    在代码5中可以看到先是对_managedObjectArray预留空间,然后将this加了进去

    //代码5
    AutoreleasePool::AutoreleasePool(const std::string &name)
    : _name(name)
    #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    , _isClearing(false)
    #endif
    {
        _managedObjectArray.reserve(150);
        PoolManager::getInstance()->push(this);
    }
    

    在代码3中还调用了getCurrentPool方法用来获取当前的内存管理池

    //代码6
    AutoreleasePool* PoolManager::getCurrentPool() const
    {
        return _releasePoolStack.back();
    }
    

    然后把this加入到当前的内存管理池中作为一个ref对象进行管理,如代码7

    //代码7
    void AutoreleasePool::addObject(Ref* object)
    {
        _managedObjectArray.push_back(object);
    }
    

    整个流程如下图所示
    管理流程

    自动内存管理的结构如下图,用一个栈来存储多个自动内存管理池,在自动内存管理池中又有若干个ref对象。
    内存管理结构

    在内存管理中主要是靠引用计数来记录对象的使用情况,当一个对象被create时会给它分配内存,并且会调用retain()方法让引用计数+1;当调用release()时会让引用计数-1,release时会检查引用计数是否为0,引用计数为0时会调用delete删除对象并释放内存。

    在每一帧结束时会清理当前的内存管理池,将每一个ref对象的引用计数都-1,这帧结束之后,内存管理池中就没有这个ref对象了,引用计数是ref自己的属性,当下一次被release时如果引用计数=0,就会被释放。

    void Director::mainLoop()
    {
    	......
        PoolManager::getInstance()->getCurrentPool()->clear();
        }
    }
    void AutoreleasePool::clear()
    {
        std::vector<Ref*> releasings;
        releasings.swap(_managedObjectArray);
        for (const auto &obj : releasings)
        {
            obj->release();
        }
    }
    

    retain()和release()只是帮助我们记录一个对象的引用次数,在程序中几乎不用手动调用。

  • 相关阅读:
    动态图片 Movie android-gif-drawable GifView
    X5SDK 腾讯浏览器内核
    AS 自动生成选择器 SelectorChapek
    Genymotion 模拟器 VirtualBox
    360加固保 安全防护 多渠道打包
    Thread 如何安全结束一个线程 MD
    面试题 HashMap 数据结构 实现原理
    nGrinder3.4 性能测试框架安装
    java内存泄漏的定位与分析
    JVM总结-内存监视手段及各区域内存溢出解决
  • 原文地址:https://www.cnblogs.com/sakuraneo/p/11992054.html
Copyright © 2011-2022 走看看