Cocos2d-x的内存管理之release()与autorelease()



龙舞奉天
2014-03-11 22:41:09

[i=s] 本帖最后由 龙舞奉天 于 2014-3-11 22:48 编辑 [/i]

[size=4] 众所周知,在java中定义的对象实例,不用考虑它什么时候被释放,因为java虚拟机会在变量不再使用时自动释放内存,但是在C++中,我们往往[color=#ff0000]使用new方法[/color]创建一个新的对象实例,当我们不需要它的时候,必须手动释放它([color=#ff0000]使用delete[/color]),不然我们的内存就会溢出,所以,内存管理对C++程序员而言是一个极其繁复的问题。而在使用cocos2d-x时我们无需再关心这个问题,因为[color=#ff0000]Cocos2d-x提供了一种类似java的内存回收机制[/color],在我们创建新的实例时,我们只需要标明该实例的属性,当我们使用完该实例时,cocos2d-x就可以帮助我们来释放它。
例如:[/size]
[b]1.dog = new CCSprite();
dog->init();
dog->autorelease();
2.apple = new CCSprite();
apple->init();

//在其他地方在此引用apple对象时
apple->retain();//保留apple对象


apple->release();[/b]
[size=4] 这两部分代码分别是创建一个不同的精灵(对象),然后初始化,在使用完的时候进行不同方法的释放。
其中1中的代码,是表明把对象放入自动回收池([color=#ff0000]CCAutoreleasePool[/color]),当回收池自身被释放的时候,他就会对池中的所有对象执行一次release()方法,实现灵活的垃圾回收。这种方法可以有效的防止内存泄露,但是他有一个重大缺陷,就是当我们在下一帧还要使用这个对象时([color=#ff0000]通常cocos2d-x会在每一帧之间释放一次自动回收池[/color]),却发现这个对象已经被释放了,所以我们使用代码2中的方法,来保持对象持续有效。
其中2中的代码,表明把一个apple对象保留,当使用结束时,再释放它。


那我们到底是使用release()还是autorelease()呢?[/size][size=4] autorelease()虽然看起来更加方便,但是它背后的垃圾回收机制同样会占用内存和CPU资源,当autorelease()过多时,会严重干扰程序进程,导致程序运行缓慢。所以,[color=#ff0000]autorelease()在一般情况下是不推荐使用的[/color](如果你觉得自己的程序变再慢也不介意的话,那请随便用……)。在需要引用的地方,[color=#ff0000]最好[/color]还是使用retain()和release()组合的方法来保留和释放对象。

但是,什么是非一般情况呢?
在cocos2d-x工程方法中,一般有如下代码:(工程方法是程序设计中的一个经典的设计模式,指的是基类中只定义创建对象的接口,将实际的实现推迟到子类中。有点类似于c++中的虚函数,但工厂方法未使用虚函数,具体请自查百度)[/size]
[b]CCObject* factoryMethod()
{
CCObject* ret = new CCObject();
return ret;
}[/b]
[size=4] 在这段代码中,隐藏着一个问题:工厂方法对ret对象的引用在函数返回(return)时已经结束,但是它[color=#ff0000]没有释放对ret的引用[/color],这样有[color=#ff0000]可能就会发生内存泄漏[/color]。在这种情况下,如果在函数return前就release了对象ret,那显然函数最后就无法return一个对象ret了。
在这种情况下,才需要我们使用autorelease()。在此函数返回时我们已失去了对ret的引用,但我们在return前添加一句[color=#ff0000]ret->autorelease()[/color];就可以返回ret对象,当自动回收池释放时,ret对象也被自动释放,不会存在诸如内存泄漏的问题。在回收池释放之前,调用者完全可以对它进行retain操作以便接管对象ret的引用权。
总而言之,除非迫不得已,大家还是多多使用retain()和release()吧[/size]{:3_55:}