【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
void Ref::retain()
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    ++_referenceCount;
}

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

release

void Ref::release()
{
    CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
    --_referenceCount;

    if (_referenceCount == 0)
    {
        ......
        delete this;
    }
}

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

autorelease

Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
Node * Node::create()
{
    Node * ret = new (std::nothrow) Node();
    if (ret && ret->init())
    {
        ret->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(ret);
    }
    return ret;
}

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

void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}

设置为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
}

在对象池的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();
    }
}

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

总结

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

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

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

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

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

推送

  • Github
https://github.com/KingSun5

结语

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值