好了,内存回收池我觉的我已经说清楚了。下面我们来看一下,通常我们的代码都是怎么写的,来看看这个自动回收机制怎么就做到自动回收了!
首先我们需要分析一下上边的代码,调用了create工厂方法以后,内部的实现是先new一个CCSprite的对象,这个时候引用计数加1,然后调用autorelease方法,将这个对象放到了自动回收池中,因为这一帧还没有结束,当然引用计数就还是1,所以打印的结果就是1,当我们调用addChild的时候,传入这个CCSprite对象,这个时候在当前层接受了这个对象以后会把它的引用计数加一,表明当前层正在使用这块内存空间,所以现在的retain就是2了。当这一帧结束的时候自动回收池会将对象的引用计数-1,所以现在就只有CCLayer在引用这个对象了,当CCLayer析构的时候,它会调用这个对象的release方法,这个时候当然就会删除了这个CCSprite对象了。所以什么是自动回收机制呢,自动就是在这一帧结束的时候将对象开始new的时候加的那个引用计数减掉,而让引擎中持有对象引用的其他类去管理这个对象,当持有者析构的时候就删除引用,引擎中的类负责retain和release,这个也算是自动吧!下面我们通过俩个例子来理解一下这个内存管理机制。
好了,运行程序我们会发现程序崩溃了,我们来分析一下。当我们创建了CCSprite对象的时候引用计数为1,并且该对象被放到了内存回收池中,在这一帧以后就会release对象一次,这个时候引用计数为0的对象当然就被释放了,我们按下按钮去调用这个对象,内存已经释放掉了,程序能不崩溃吗?下面我们来将代码改成如下的这样,看看效果。
1 | this ->m_sprite = CCSprite::create( "HelloWorld.png" ); |
2 | CCLog( "%d" , this ->m_sprite->retainCount()); |
3 | this ->m_sprite->retain(); |
4 | CCLog( "%d" , this ->m_sprite->retainCount()); |
这个时候运行起来程序,在按钮的函数调用的时候你会看到输出的引用计数都是1,因为我们已经手动的retain了一下这个对象,虽然自动回收池将它release了一下,但是它的引用计数任然为1。既然我们retain了,所以在层析构的时候记得要release啊。这样内存才不会泄露!还有一个就是CCArray的例子,下面来看一下。
1 | bool HelloWorld::init() |
10 | CC_BREAK_IF(! CCLayer::init()); |
11 | CCSprite* bomb1 = CCSprite::create( "CloseNormal.png" ); |
12 | CCSprite* bomb2 = CCSprite::create( "CloseNormal.png" ); |
13 | CCSprite* bomb3 = CCSprite::create( "CloseNormal.png" ); |
14 | CCSprite* bomb4 = CCSprite::create( "CloseNormal.png" ); |
15 | CCSprite* bomb5 = CCSprite::create( "CloseNormal.png" ); |
16 | CCSprite* bomb6 = CCSprite::create( "CloseNormal.png" ); |
25 | m_pBombsDisplayed = CCArray::create(bomb1,bomb2,bomb3,bomb4,bomb5,bomb6,NULL); |
27 | this ->scheduleUpdate(); |
35 | void HelloWorld::update(ccTime dt) |
40 | void HelloWorld::refreshData() |
42 | m_pBombsDisplayed->objectAtIndex(0)->setPosition(cpp(100,100)); |
其实这个原理和上边的例子是差不多的,我们创建了一个CCArray的对象,这个时候同样是没有添加到其他的层中的,所以在这一帧结束的时候就会将它的引用计数减1变成0,所以,再次使用的时候肯定就会出错了!在使用cocos2dx的内存管理的时候如果我们是通过工厂的方法创建的,并且add到了其他的层中的时候这个时候我们多数是不用担心的,但是如果你是通过new的方法创建的CCObject子类的对象,这个时候记住要在析构的时候release这个对象,如果在使用过程中你retain了对象,同样记住要release。本人总结的是,当我们调用函数传递CCObject子类对象的时候,在接受的时候我们都应该去retain一下,这样代表的是我要引用这块内存空间,什么时候你不再引用这块内存空间了,就release一下。