1 C++内存管理
A 栈上的空间 |
自生自灭,不用管理 |
B 堆上的空间 |
手动new,手动delete,否则产生内存泄漏 |
2 内存管理的难处
管理原则,谁申请谁释放 |
3 内存的智能管理
主要有两种实现智能管理内存的技术,一种是引用计数,一是垃圾回收。
引用计数:通过给每个对象维护一个引用计数器,记录该对象当前被引用的次数。当对象增加一次引用时,计数器加1;而对象失去一次引用时,计数器减1;当引用计数为0 时,标志着该对象的生命周期结束,自动触发对象的回收释放。引用计数解决了对象的生命周期管理问题,但堆碎片化和管理烦琐的问题仍然存在。
垃圾回收:它通过引入一种自动的内存回收器,试图将程序员从复杂的内存管理任务中完全解放出来。它会自动跟踪每一个对象的所有引用,以便找到所有正在使用的对象,然后释放其余不再需要的对象。垃垃圾回收器通常是作为一个单独的低级别的线程运行的,在不可预知的情况下对内存堆中已经死亡的或者长时间没有使用过的对象进行清除和回收。
4 cocos2dx内存管理
A 手动管理
Cocos2dx采用工厂方法创建对象,所有生成的对象均在堆上,所以Cocos2dx采用了引用计数的方法管理内存。具体实现:
B 案例说明:
T09Memory.h |
#ifndef _T09Memory_ #define _T09Memory_
#include "cocos2d.h" USING_NS_CC; class T09Memory :public CCLayer { public: static CCScene * scene(); CREATE_FUNC(T09Memory); bool init();
CCSprite * spr; void mySchedule(float dt); };
#endif |
T09Memory.cpp |
#include "T09Memory.h"
CCScene * T09Memory::scene() { CCScene *scene = CCScene::create(); T09Memory *layer = T09Memory::create(); scene->addChild(layer); return scene; }
bool T09Memory::init() { CCLayer::init();
spr = new CCSprite(); //CCLog("retain count %d", spr->retainCount()); spr->retain(); //引用计数加1 CCLog("use spr->retatin : retain count %d", spr->retainCount()); //spr->release(); //CCLog("retain count %d", spr->retainCount());
spr->init(); spr->release();
//autorelease()也release了但是不一定就释放了,而是遵循延时释放 spr->autorelease(); //延时释放 //CCLog("retain count %d", spr->retainCount()); addChild(spr); //这里引用,这里引用加1 CCLog("retain count %d", spr->retainCount());
//通过下面可以证明上面已经释放内存了 schedule(schedule_selector(T09Memory::mySchedule),2); return true; }
void T09Memory::mySchedule(float dt) { CCLog("retain count %d", spr->retainCount()); } |
运行结果: |
C retain()本质
D autorelease()本质(延迟释放内存)
5 CCArray
A 类关系图
B CCArray继承自CCObject,而非CCNode,没有办法加到渲染树中去,但是参加了内存托管。所以应该手动处理。
示例:
Array = CCArray::create(); Array->retain(); CCSprite *spr = CCSprite::create(); array->addObject(spr); CCMenuItem *item = CCMenuItemImage::create(“closeNormal.png” “CloseSelected.png”, this, menu_selector(T09Memory::menuCallBack) ); CCMenu * menu = CCMenu::create(item,NULL); addChild(menu); |
Void T09Memory::menuCallBack(CCObject *obj){ //获得array中的第一个值 array->objectAtIndex(0); } |
C 例外中的例外
void T09Memory::onExit(){ array->release(); } |
C CCArray的案例:
T09Memory.h |
#ifndef __T09Memory_H__ #define __T09Memory_H__
#include "cocos2d.h" USING_NS_CC; class T09Memory :public CCLayer { public: static CCScene * scene(); CREATE_FUNC(T09Memory); bool init();
CCSprite * spr; void menuCallback(CCObject * obj);
CCArray *array;
void onExit(); };
#endif |
T09Memory.cpp |
#include "T09Memory.h"
CCScene * T09Memory::scene() { CCScene *scene = CCScene::create(); T09Memory *layer = T09Memory::create(); scene->addChild(layer); return scene; }
bool T09Memory::init() { CCLayer::init(); array = CCArray::create(); array->retain(); spr = CCSprite::create("CloseNormal.png"); CCSprite * spr2 = CCSprite::create("p_3_01.png"); array->addObject(spr); array->addObject(spr2); //添加一个精灵 addChild(spr);
//通过下面的方式实现鼠标点击上去后图片切换的效果 CCMenuItem * item = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(T09Memory::menuCallback));
CCMenu * menu = CCMenu::create(item, NULL); //添加CCMenuItem条项 addChild(menu);
return true; }
void T09Memory::menuCallback(CCObject * obj) { array->objectAtIndex(0); //下面的一句将CCArray中的第二个参数去除来了 CCSprite * spr = (CCSprite *)array->objectAtIndex(1); spr->setPosition(ccp(100,200)); addChild(spr); }
//在层退出的时候调用 void T09Memory::onExit() { //降引用计数减1 array->release(); } |
运行结果: 点击前: 点击后: |