Cocos2d-x 内存机制浅析

来源:互联网 发布:alpha软件go下载 编辑:程序博客网 时间:2024/05/17 23:54

一、概述

为了方便内存的管理和自动内存回收,Cocos2d-x引入了引用计数机制,包装了c++原本的new、 delete操作。简单来说,对象的引用计数会随着retain()和 release()的调用增加和减少,当release()调用时,如果引用计数为零,那么,这个object就被析构。

下面,我们对照源码,详细分析一下引用计数机制。


二、原理分析

我们首先看一下实现引用计数机制的几个关键类 cocos2d::Ref  AutoreleasePool   PoolManager

想要使用自动内存回收机制,我们的对象就要继承自 Ref 这个类。

Ref 有一个很重要的属性,那就是_referenceCount,用来记录当前的引用计数,默认值是1
retain()方法,调用后,_referenceCount加1;
release()方法,调用后,_referenceCount减1;如果_referenceCount == 0,调用 delete this方法,析构当前对象。
autorelease()方法,把自己添加到当前对象池(AutoreleasePool)中
Ref* Ref::autorelease()
{
PoolManager::getInstance()->getCurrentPool()->addObject(this);
return this;
}

AutoreleasePool是一个自动回收的对象池,每当调用AutoreleasePool::addObject时,他会把参数对象添加到一个std::vector<Ref*>类型的vector里;等到外部调用clear()方法时,会遍历该vector里面所有的Ref*对象,调用他们的 release()方法。  AutoreleasePool::clear()什么时候调用呢?我们继续来看这个管理AutoreleasePool的类:PoolManager

PoolManager的功能比较简单,他可以push一个AutoreleasePool到栈顶,或者,pop一个栈顶的AutoreleasePool;

最后,我们找到引擎的主循环处代码DisplayLinkDirector::mainLoop(),可以看到循环的最后,会对当前在栈顶的AutoreleasePool实例调用 clear()方法PoolManager::getInstance()->getCurrentPool()->clear();


影响引用计数的因素有很多,addchild 、removechild 、runAction等等,但原理都是一样的,这篇文章不再详细介绍。


三、常见错误的操作和正确做法

错误的做法:

auto obj = Node::create();//Ref = 1

    obj->autorelease();  //错误,create方法里已经调用了obj->autorelease(),这里反复调用的话,会导致AutoreleasePool里push进去2个该对象,当Pool.clear()时,调用第一次 obj.release()后,obj就已经被析构了,第二次调用就成了调用一个野指针的release()方法,引发不可预料的异常。

auto obj = Node::create();
  obj->release();//这里就被析构了,之后AutoreleasePool::clear()时又会尝试release他,出错


正确的做法:

auto obj = Node::create(); // ref = 1;
obj->retain();  // ref = 2;
obj->autorelease();  //ref = 2;


0 0