• 【cocos2dx】学习记录,Node的自动释放(autorelease)


    前言

    在整理一个功能的时候,发现做了一个对象池用来缓存ScrollView的子节点,这里面手动的去retain和release对象池内的Node,碰到了一些小问题记录一下

    问题整理

    • 问题1:

    Node创建后不添加,引用计数即为1

    • 问题2:

    创建Node后手动retain,引用计数为2,一帧后引用计数变为了1

    • 问题3:

    引用计数为1的Node,先release再添加到场景上出问题,Node不存在

    引用、释放、自动释放

    之前也就大概的看了一下引用和释放的逻辑,有些细节没看到,趁机再看了一下造成问题的原因

    retain

    : _referenceCount(1) // when the Ref is created, the reference count of it is 1
    
    • 1
    void Ref::retain()
    {
        CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
        ++_referenceCount;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在Ref内最基础的方法,引用,很简单这里,Ref在创建的时候,引用计数默认为1,retain被调用的话,引用计数会加一

    release

    void Ref::release()
    {
        CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
        --_referenceCount;
    
        if (_referenceCount == 0)
        {
            ......
            delete this;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    release被调用的时候,引用计数会减一,在引用计数为0后,会释放掉当前节点,所以问题3中不能先释放

    autorelease

    Ref* Ref::autorelease()
    {
        PoolManager::getInstance()->getCurrentPool()->addObject(this);
        return this;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    Node * Node::create()
    {
        Node * ret = new (std::nothrow) Node();
        if (ret && ret->init())
        {
            ret->autorelease();
        }
        else
        {
            CC_SAFE_DELETE(ret);
        }
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    本次的重点是这个autorelease,之前一直没注意,Node在创建后会被默认设置为一个自动释放,自动释放干了什么呢,如下所示

    void AutoreleasePool::addObject(Ref* object)
    {
        _managedObjectArray.push_back(object);
    }
    
    • 1
    • 2
    • 3
    • 4

    设置为autorelease后,当前节点会被添加到AutoreleasePool的_managedObjectArray数组内

    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
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在对象池的clear的方法里,会吧_managedObjectArray数组内的节点都release一遍,再清空数组

    void Director::mainLoop()
    {
        if (_purgeDirectorInNextLoop)
        {
            _purgeDirectorInNextLoop = false;
            purgeDirector();
        }
        else if (_restartDirectorInNextLoop)
        {
            _restartDirectorInNextLoop = false;
            restartDirector();
        }
        else if (! _invalid)
        {
            drawScene();
         
            // release the objects
            PoolManager::getInstance()->getCurrentPool()->clear();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在主循环内没帧都会调用对象池的clear方法,所以其实当前节点创建后,下一帧引用计数就会自动-1,如果没有用到这个节点,在下一帧就会被释放掉了

    总结

    综上所述,我们已经可以很清楚的看明白cocos引用计数的原理

    Ref在被创建的时候,默认引用计数+1

    继承自Ref的Node在初始化的时候,会默认设置成autorelease

    被设置成autorelease状态的节点,如果引用计数<=1,也就是创建后不添加为子节点,也不手动retain,那么下一帧就会被自动释放掉

    想要常驻内存不被释放,可以选择添加为别的节点的子节点,在addChild的时候,引用计数会+1,或者手动retain调用一下

    推送

    • Github
    https://github.com/KingSun5
    
    • 1

    结语

    若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。
    QQ交流群:806091680(Chinar)
    该群为CSDN博主Chinar所创,推荐一下!我也在群里!
    本文属于原创文章,转载请著名作者出处并置顶!!

  • 相关阅读:
    aso标题关键词可以重复吗
    如何每天自动发送心灵鸡汤、正能量语录
    Web前端开发技术课程大作业_ 关于美食的HTML网页设计——HTML+CSS+JavaScript在线美食订餐网站html模板源码30个页面_
    Oracle-12c新功能基于时间点recover table
    javascript二维数组(9)toString的用法
    键盘盲打是练出来的
    博客从 CloudBase 迁移至云主机
    学生党蓝牙耳机怎么选?适合realme手机的高端蓝牙耳机推荐
    stm32f4单片机强制类型转换为float程序跑飞问题
    net-java-php-python-教材管理系统计算机毕业设计程序
  • 原文地址:https://blog.csdn.net/Mr_Sun88/article/details/127431884