cocos2d-x 3.0 内存管理

参考文章:

http://blog.csdn.net/musicvs/article/details/8689345

http://blog.csdn.net/honghaier/article/details/8160519

http://goldlion.blog.51cto.com/4127613/784134


cocos2d-x采用了引用计数机制来进行内存管理。每个对象都有一个用来控制生命周期的引用计数器。在对象通过构造函数创建时,该对象的引用计数值就被赋值为1,表示对象是由创建者所引用。因为如Scene、Layer等类都是继承自Ref类,而C++中,一个类的构造函数总是会先调用父类的构造函数,然后再执行自身代码。而Ref类中的无参构造函数,就是把引用计数值初始化为1。

retain(),令指针所指向的对象的引用计数值加1,表示获取该对象的引用权。

release(),引用结束时,调用该方法使对象的引用计数值减1,表示释放该对象的引用权。

autolease(),其作用就是将对象放入自动回收池。cocos2d-x会保证每一帧结束后释放一次回收池,而调用了autorelease()方法的对象,将会在自动回收池释放的时候被释放一次。但也只是释放一次而已。


注意这样一句话:当引用计数为0时,标志着该对象的生命周期结束,自动触发对象的回收释放。

疑问:怎么自动触发对象的回收释放?

解答:这是因为release()进行的操作是,先把引用计数减1,再判断是否为0,如果为0,就用delete删除对象。


工厂方法

工厂方法,泛指一切生成并返回一个对象的静态函数。

代码1:

static HelloWorldScene* create(){
	HelloWorldScene *pRet = new HelloWorldScene();
	return pRet;
}

代码2:

static HelloWorldScene* create(){
	HelloWorldScene *pRet = new HelloWorldScene();
	delete pRet;
	return pRet;
}

代码3:

static HelloWorldScene* create(){
	HelloWorldScene *pRet = new HelloWorldScene();
	pRet->autorelease();
	return pRet;
}

代码1,会造成 内存泄露,当然可以在析构函数中delete。但是不知道在其他地方是否还有对该对象的引用,如果析构函数中释放了该资源,那么其他地方如果还有对该对象的引用,那么就会发生错误。

代码2,释放了资源,再返回pRet,此时pRet是一个野指针

代码3,为了返回pRet对象返回给接收者,需要对它进行一次autorelease操作。autorelease方法,对象直到自动回收池释放之前是不会被真正释放掉的。我们可以有足够的时间来对它进行retain操作以便接管pRet对象的引用权(记得配对使用release)


来看一段代码

Scene* HelloWorld::createScene()
{
	auto scene = Scene::create();
	auto layer = HelloWorld::create();

	log("%u", layer->getReferenceCount()); //引用计数值为1

	scene->addChild(layer);

	log("%u", layer->getReferenceCount()); //引用计数值为2

	return scene;
}

layer指针所指的对象,是通过HelloWorld::create()创建的,create()方法中使用了new和autolease()。

new会调用父类Ref的默认无参构造函数,把引用计数值初始化为1。

此时layer所指对象的引用计数值为1。

scene->addChild(layer),layer被引用,那么引用计数值应该加1,为什么这里不用retain()呢?因为addChild()里已经为我们retain()了一次。而且对应的release()也不用我们考虑了。那么此时的引用计数值自然就为2了。

在整个场景销毁时,会把layer的引用计数值减1,那么2-1=1,引用计数值变为1,而因为layer是autorelease的,及layer是放到自动释放池的,自动释放池的对象在每一帧结束后都会调用一次release,此时计数值为1的对象再进行一次release,计数值就变为0,而且调用了delete释放对象资源。

所以这里就要思考autorelease()的作用,看代码3,试想一下,如果返回的HelloWorldScene对象没有被引用,那么引用计数值为1,且pRet放到自动释放池,那么当前帧结束后就会对自动释放池中的每个对象进行一次release,此时对pRet所指的对象(计数值为1)进行一次release,就会把对象释放掉了。不会造成内存泄露。

在new对象以后,使用autorelease(),就不用考虑何时delete的问题。剩下要做的,就是我们自己手动retain()和release(),对象增加了一次引用,就retain()一下,记得retain()和release()是配对出现的,有retain()就有release(),一般release()可以在析构函数中进行。

另外,autorelease只会在下一帧减1,而不是每一帧都减1。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值