cocos2dx 内存管理.docx
- 文档编号:25270819
- 上传时间:2023-06-06
- 格式:DOCX
- 页数:17
- 大小:61.79KB
cocos2dx 内存管理.docx
《cocos2dx 内存管理.docx》由会员分享,可在线阅读,更多相关《cocos2dx 内存管理.docx(17页珍藏版)》请在冰豆网上搜索。
cocos2dx内存管理
你应该知道的cocos2d-x 内存管理
你的cocos2d-x里面指针用的多么?
在指针乱飞的程序中你是否会感到不安了?
不管你们有没有,反正我是有的。
cocos2d里面管理内存采用了引用计数的方式,咋眼一看以为是智能指针,但那确实是简单的采用了智能指针中的引用计数,具体的来说就是CCObject里面有个成员变量m_uReference(计数);
m_uReference的变化
对象初始化:
m_uReference =1
retain:
++m_uReference
release:
--m_uReference,if(m_uReference==0)delete对象
addxxx:
一般具有add语义代码会retain对象,比如说addChild
removexxx:
一般具有remove语句的代码会release对象
CCPoolManager(以池的方式管理内存)
cocos2d-x采用了以池的方式管理内存,前提是给对象来了个autorelease的操作,这个时候对象有个属性
m_bManaged =true;他和我们手动的release有什么区别了?
其实也就是调用时机不一样,CCPoolManager会在每帧动画结束后调用pop方法将池中的对象release掉
这里会怎样release了?
在CCPoolManager的clear方法中首先会遍历所有池中元素,将m_bManaged =false(注意这里),后将所有池中的所有对象release掉,当对象的m_bManaged==false的时候,以前在池中的对象现在就不会再在池中,也就是说下次的一个帧的动画结束后,被先前CCPoolManager调用pop方法release的对象(如果还存在)就不会再被pop方法release了(CCPoolManager的最终作用就是将对象的引用计数减一而已,除此之外没有什么其他神奇的功能)
当父节点被析构时,其所有的子节点都会相应执行release,后将父节点重置为NULL
coco2d-x中很多用静态方法创建的对象都会自动由CCPoolManager来管理内存,举个例子
在我们的操作下,不是说由CCPoolManager管理的内存就是没有问题的,他和我们手动release就是一个调用时机的差别,而我们所要关注的是当前程序的运行环境和对象的m_uReference计数,不管怎样你都有权采用release或则retain的方式来改变对象的生命周期,这时你的自由!
使用过Cocos2d-x都知道,其中有一套自己实现的内存管理机制,不同于一般C++的编写常规,而在使用前,了解其原理是有必要的,网上已经有很多对内部实现详细解说的文章。
而对于使用者而言,并不需要对其内部有很深的了解,注重其“机制”,而非内部实现,在这里只是简单的聊一聊它的管理方式以及使用,固为浅说。
无用对象与管理对象
Cocos2d-x将会在下一帧自动清理无用的对象,什么是无用的对象,通过create()方法创建的就是无用的对象。
为了简要说明,代码的组织设计一切从简,我们创建了两个辅助类和一个容器类BaseLayer,在BaseLayer之上管理内部对象,并观察它是怎么自动管理对象的。
实现了其构造函数方法和析构函数,并做些日志打印,以方便我们观察:
1.1.class LSLayer:
public CCNode {
2.2.public:
3.3. virtual bool init() {
4.4. CCLog("LSLayer().init()");
5.5. return true;
6.6. };
7.7.
8.8. CREATE_FUNC(LSLayer);
9.9.
10.10. LSLayer(){
11.11. CCLog("LSLayer().()");
12.12. };
13.13. ~LSLayer() {
14.14. CCLog("LSLayer().~()");
15.15. };
16.16.};
17.17.
18.18.class LSSprite:
public CCNode {
19.19.public:
20.20. virtual bool init() {
21.21. CCLog("LSSprite().init()");
22.22. return true;
23.23. };
24.24.
25.25. CREATE_FUNC(LSSprite);
26.26.
27.27. LSSprite(){
28.28. CCLog("LSSprite().()");
29.29. };
30.30. ~LSSprite() {
31.31. CCLog("LSSprite().~()");
32.32. };
33.33.};
34.34.
35.35.class BaseLayer:
public CCLayer {
36.36.public:
37.37. virtual bool init(){
38.38. CCLog("BaseLayer().init()");
39.39. // 我们创建了两个 “无用”对象
40.40. LSLayer* layer = LSLayer:
:
create();
41.41. LSSprite* sprite = LSSprite:
:
create();
42.42. // 使用了 layer 变为受“管理”的对象
43.43. this->addChild(layer);
44.44.
45.45. return true;
46.46. };
47.47.
48.48. CREATE_FUNC(BaseLayer);
49.49.
50.50. BaseLayer(){
51.51. CCLog("BaseLayer().()");
52.52. };
53.53. ~BaseLayer(){
54.54. CCLog("BaseLayer().~()");
55.55. };
56.56.};
如上所示,我们在BaseLayer中创建了两个对象,layer和sprite,而只使用了layer,如果要运行上面的BaseLayer代码,我们需要创建一个BaseLayer的层对象,并将它添加到运行的场景或者层中:
addChild(BaseLayer:
:
create());,以保证BaseLayer开始运行,现在我们分析一下运行的结果:
1.1.// 由 addChild(BaseLayer:
:
create()); 方法开始,创建并初始化了 BaseLayer 层
2.2.cocos2d-x debug info [BaseLayer().()]
3.3.cocos2d-x debug info [BaseLayer().init()]
4.4.// BaseLayer init 方法我们创建了两个对象
5.5.cocos2d-x debug info [LSLayer().()]
6.6.cocos2d-x debug info [LSLayer().init()]
7.7.cocos2d-x debug info [LSSprite().()]
8.8.cocos2d-x debug info [LSSprite().init()]
9.9.// 对象创建完成,紧接着这“无用”对象便已经释放了,而另一个已经使用的对象没有释放
10.10.cocos2d-x debug info [LSSprite().~()]
通过上面两个例子对比,对cocos2d-x的对象管理有了初步的认识,它会自动清理“无用对象”。
为了区分概念,我们将另一种对象称之为“管理对象”,它是受管理的,有用的对象。
比如上文中的layer。
这也算初步认识,当然,这至少解决了我们这样一个疑问:
我们在场景初始化的时候,通过create()创建了成员变量,以备需要的时候使用,但发现在使用的时候这个对象已经不存在了,从而导致程序崩溃。
管理对象不用之时立即回收
我们再继续演变BaseLayer的实现,以方便我们观察在每一帧对象的情况,添加实现了定时器功能:
1.1.class BaseLayer2:
public CCLayer {
2.2.public:
3.3. virtual bool init(){
4.4. CCLog("BaseLayer2().init()");
5.5. // 启用定时器,自动在每一帧调用 update 方法
6.6. this->scheduleUpdate();
7.7. return true;
8.8. };
9.9.
10.10. // 定义 update 统计
11.11. int updateCount;
12.12. LSLayer* layer;
13.13. LSSprite* sprite;
14.14.
15.15. virtual void update(float fDelta){
16.16. // 为了方便观察,不让 update 内部无止境的打印下去
17.17. if (updateCount < 3){
18.18. updateCount ++;
19.19. CCLog("update index:
%d", updateCount);
20.20.
21.21. // 在不同的帧做相关操作,以便观察
22.22. if (updateCount == 1){
23.23. layer = LSLayer:
:
create();
24.24. this->addChild(layer);
25.25. sprite = LSSprite:
:
create();
26.26.
27.27. } else if (updateCount == 2){
28.28. this->removeChild(layer, true);
29.29.
30.30. } else if (updateCount == 3){
31.31.
32.32. }
33.33.
34.34. CCLog("update index:
%d end", updateCount);
35.35. }
36.36. };
37.37.
38.38. CREATE_FUNC(BaseLayer2);
39.39.
40.40. BaseLayer2():
41.41. updateCount(0),
42.42. layer(NULL),
43.43. sprite(NULL)
44.44. {
45.45. CCLog("BaseLayer2().()");
46.46. };
47.47. ~BaseLayer2(){
48.48. CCLog("BaseLayer2().~()");
49.49. };
50.50.};
51.51.
52.52.// 打印如下
53.53.cocos2d-x debug info [BaseLayer2().()]
54.54.cocos2d-x debug info [BaseLayer2().init()]
55.55.// 第一帧创建两个对象
56.56.cocos2d-x debug info [update index:
1]
57.57.cocos2d-x debug info [LSLayer().()]
58.58.cocos2d-x debug info [LSLayer().init()]
59.59.cocos2d-x debug info [LSSprite().()]
60.60.cocos2d-x debug info [LSSprite().init()]
61.61.cocos2d-x debug info [update index:
1 end]
62.62.// 我们看到 sprite 无用对象在 第一帧和第二帧之间被释放
63.63.cocos2d-x debug info [LSSprite().~()]
64.64.cocos2d-x debug info [update index:
2]
65.65.// 在第二帧移除管理对象,可以看到它是立即释放,在 index:
2 end 之前
66.66.cocos2d-x debug info [LSLayer().~()]
67.67.cocos2d-x debug info [update index:
2 end]
68.68.cocos2d-x debug info [update index:
3]
69.69.cocos2d-x debug info [update index:
3 end]
与无用对象不同的是,管理对象在不用之时,立即释放,这决定着如果想在其它地方使用此对象,在“完全”不用之前,一定要有所作为。
重写update方法如下:
1.1.virtual void update(float fDelta){
2.2. // 为了方便观察,不让 update 内部无止境的打印下去
3.3. if (updateCount < 3){
4.4. updateCount ++;
5.5. CCLog("update index:
%d", updateCount);
6.6.
7.7. // 在不同的帧做相关操作,以便观察
8.8. if (updateCount == 1){
9.9. layer = LSLayer:
:
create();
10.10. this->addChild(layer);
11.11. sprite = LSSprite:
:
create();
12.12. CCLog("%d", layer);
13.13. } else if (updateCount == 2){
14.14. layer->retain();
15.15. this->removeChild(layer, true);
16.16. CCLog("%d", layer);
17.17. } else if (updateCount == 3){
18.18. layer->release();
19.19. if (layer){
20.20. CCLog("%d", layer);
21.21. }
22.22. }
23.23.
24.24. CCLog("update index:
%d end", updateCount);
25.25. }
26.26.};
27.27.
28.28./// 打印如下
29.29.cocos2d-x debug info [update index:
1]
30.30.cocos2d-x debug info [LSLayer().()]
31.31.cocos2d-x debug info [LSLayer().init()]
32.32.cocos2d-x debug info [LSSprite().()]
33.33.cocos2d-x debug info [LSSprite().init()]
34.34.cocos2d-x debug info [147867424]
35.35.cocos2d-x debug info [update index:
1 end]
36.36.cocos2d-x debug info [LSSprite().~()]
37.37.cocos2d-x debug info [update index:
2]
38.38.// 第二帧并没有释放 layer,因为它还是有用的管理对象
39.39.cocos2d-x debug info [147867424]
40.40.cocos2d-x debug info [update index:
2 end]
41.41.cocos2d-x debug info [update index:
3]
42.42.// 完全弃用,立即释放
43.43.cocos2d-x debug info [LSLayer().~()]
44.44.// 但是 layer 对象的地址还是可用的
45.45.cocos2d-x debug info [147867424]
46.46.cocos2d-x debug info [update index:
3 end]
在完全不用之前,要有所作为。
如果我们将第二帧中的layer->retain();放在this->removeChild(layer,true);之后呢,我们知道在removeChild之后是立即释放的,此时layer对象已经不存在了,而layer所指向的内存地址是个无效地址。
如果你的程序继续运行,那么一定会出现内存错误。
如果程序直接错误异常退出,倒也罢了,怕就怕,程序可能继续运行,layer虽然是无效地址,但并不是NULL,可能所指向的地址可用,可能还能继续执行,更可能的还能继续layer->retain();操作。
这会影响我们的判断,程序真的有问题么。
如果留下了这种隐患,那么排除错误的难度会大大加深。
比如程序莫名其妙的退出,时好时坏!
(经过一叶的测试,这种情况是可能发生的,而且频率相当高,测试平台:
Linux平台,Android平台可能性稍低)
第三帧我们通过if(layer)判断对象是否可用,如果可用我们继续操作layer,这样的使用方式也将会留下内存隐患,因为这样的判断是能通过的,但却是不一定能够正确使用的。
一般而言,我们不一定需要if(layer)诸如此类的判断,这也是不推荐的。
管理对象,谁使用,那么谁就是可控的!
如果在对象销毁之前谁retain(),那么在release()之前,它无需判断即可使用。
谁addXXX使用,一般能通过getXXX获取。
简而言之,谁使用(引用),你就找谁就行了,不论是获取,或者移除。
我们前面所言,管理对象不用之时,立即回收,那么我们在同一帧使用,然后移除呢?
我们继续改写update方法,验证想法:
1.1.virtual void update(float fDelta){
2.2. // 为了方便观察,不让 update 内部无止境的打印下去
3.3. if (updateCount < 3){
4.4. updateCount ++;
5.5. CCLog("update index:
%d", updateCount);
6.6.
7.7. // 在不同的帧做相关操作,以便观察
8.8. if (updateCount == 1){
9.9. layer = LSLayer:
:
create();
10.10. this->addChild(layer);
11.11. this->removeChild(layer, true);
12.12. } else if (updateCount == 2){
13.13.
14.14. } else if (updateCount == 3){
15.15.
16.16. }
17.17.
18.18. CCLog("update index:
%d end", updateCount);
19.19. }
20.20.};
21.21.
22.22./// 其打印如下
23.23.cocos2d-x debug info [update index:
1]
24.24.cocos2d-x debug info [LSLayer().()]
25.25.cocos2d-x debug info [LSLayer().init()]
26.26.cocos2d-x debug inf
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- cocos2dx 内存管理 内存 管理