cocos2dx内存管理机制学习笔记,源码分析

cocos2dx面试时最容易考的问题就是内存管理,我自己都被问的烦了,本文分析透彻,源码详尽,可以避免在这个问题上失分

cocos2dx的内存管理采用引用计数的策略,百度百科的引用计数解释如下:

 

通过源代码分析,作出以下总结:

1.Ref类中的_referenceCount成员变量用作引用计数

protected:
    /// count of references
    unsigned int _referenceCount;

2.Ref的构造函数为_referenceCount赋值为1

Ref::Ref()
: _referenceCount(1) // when the Ref is created, the reference count of it is 1

3.retain() 执行++_referenceCount,release()执行--_referenceCount,并且当_referenceCount ==0时,释放对象.

 

void Ref::retain()
{
    ++_referenceCount;
}
void Ref::release()
{
	--_referenceCount;
	if (_referenceCount == 0)
	{
		delete this;
	}
}

4.autorelease()会在自动释放池中,添加一个对象(向量尾部插入新对象),AutoreleasePool类中,使用向量容器vector<Ref*> _managedObjectArray保存对象。

Ref* Ref::autorelease()
{
    PoolManager::getInstance()->getCurrentPool()->addObject(this);
    return this;
}
void AutoreleasePool::addObject(Ref* object)
{
    _managedObjectArray.push_back(object);
}
std::vector<Ref*> _managedObjectArray;

5.通过create()创建的对象,会执行new(),init(),autorelease()几个函数,即对象被放入自动释放池,这类对象若不addchild()会在下一帧释放,若想保留可手动retain(),不需要时手动release()

 

Scene* Scene::create()
{
    Scene *ret = new (std::nothrow) Scene();
    if (ret && ret->init())
    {
        ret->autorelease();
        return ret;
    }
    else
    {
        CC_SAFE_DELETE(ret);
        return nullptr;
    }
}

6.导演类的mainLoop()执行drawScene()画完一帧后,执行 PoolManager::getInstance()->getCurrentPool()->clear();clear()有2个功能:

(1)

std::vector<Ref*> releasings;
releasings.swap(_managedObjectArray);

 

用新向量releasings和向量_managectArray互换,将_managedObjectArray内容清空,长度清0,这么做是为了让自动释放池中的对象只自动执行一次release()判断是否释放

(2)

 

for (const auto &obj : releasings)
{
    obj->release();
}

 

遍历自动释放池中的对象逐一调用一次release(),完整代码如下:

 

void DisplayLinkDirector::mainLoop()
{
    if (_purgeDirectorInNextLoop)
    {
        _purgeDirectorInNextLoop = false;
        purgeDirector();
    }
    else if (_restartDirectorInNextLoop)
    {
        _restartDirectorInNextLoop = false;
        restartDirector();
    }
    else if (! _invalid)
    {
        drawScene();//画一帧
     
        // release the objects
        PoolManager::getInstance()->getCurrentPool()->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
}

7.addChild(Node *child)会执行child->retain();removechild()会执行child->release();

 

 

void Node::addChild(Node *child)
{
    CCASSERT( child != nullptr, "Argument must be non-nil");
    this->addChild(child, child->_localZOrder, child->_name);
}
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);
	//以下省略
}
void Node::insertChild(Node* child, int z)
{
    _transformUpdated = true;
    _reorderChildDirty = true;
    _children.pushBack(child);
    child->_localZOrder = z;
}
void pushBack(T object)
{
     CCASSERT(object != nullptr, "The object should not be nullptr");
     _data.push_back( object );
     object->retain();
}

 

 

8.当对象的指针作为形参时,函数体内需retain()形参 (形参被其他指针保留了,所以需retain),

 

release被赋值指针(被赋值指针不需要使用原先指向的对象了,所以需release),再赋值.

 

void testFun(Ref* obj1)
{
	obj1->retain();
	obj2->release();
	obj2 = obj1;
}

 

面试环节

问:cocos2d-x内存管理机制如何实现?

答:cocos2d-x使用引用计数机制实现内存自动管理。有一个基类Ref,Ref中通过referenceCount变量保存计数,构造函数中会把新建对象的计数赋值为1,Ref中retain可将计数自加,release可将计数自减,并且判断当计数为0时进行释放。新建出的节点加到父节点时会调用retain,从父节点移除时会调用release。有一个自动释放池类AutoreleasePool,其中有个autorelease函数,可将对象放到自动释放池的一个向量容器中,通过CREATE宏创建出来的函数都会执行autorelease操作。在每一帧结束时会调用自动释放池的clear函数,clear会将自动释放池中所有对象调用release函数。因此新建出来的对象其引用计数的变化过程为:创建出来构造函数赋值为1,加到父节点后变为2,所在帧结束时由于调用了clear又变为1这样一个过程。

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ellis1970

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值