Cocos2d-x HelloWorld的全面解析

1.class 图地址下载:

http://download.csdn.net/detail/l695863436/5965529

现在我们来分析以下代码:


 CCScene *scene = CCScene::create();

运行的时序图地址:

http://download.csdn.net/detail/l695863436/5965529

CCScene::create()函数如下:

单步调试。先会调用CCScene()的构造函数:


代码如下:

其中bool m_bIgnoreAnchorPointForPosition///< true if the Anchor Point will be (0,0) when you position the CCNode, false otherwise. Used by CCLayer and CCScene.

 m_bIgnoreAnchorPointForPosition = true;   //  CCLayerCCScene 设置描点

 m_bIgnoreAnchorPointForPosition = flase;  //  忽略描点 

对象创建成功后 将调用:

 pRet->init()

我们找到pRet->init()的代码如下:

我们先看看这行代码:

pDirector = CCDirector::sharedDirector();

static CCDisplayLinkDirector *s_SharedDirector = NULL;

由于CCDisplayLinkDirector继承CCDirector所以可以返回父类指针,现在我们来看:

 CCDisplayLinkDirector(void

        : m_bInvalid(false)

    {}

其中m_bInvalid = false; // 我是这么理解的,导演可以开工,也就是所以的动作执行有效。

m_bInvalid = true; // 我是这么理解的,导演不能开工,所有的动作无效。

来看看这句代码:

s_SharedDirector->init(); //抱歉每个数据成员代表什么意思没有仔细研究。

该函数初始化导演类需要的数据,如:FPS,是否可以响应触屏等等信息。

场景类创建并初始化完了后,开始调用

pRet->autorelease(); // 自动管理内存,coco的内存管理是这篇博客重点分析的对象。

好的,我们转到定义处,发现他调用的是CCObject::autorelease



2.内存管理:

该内存管理是通过栈的形式进行管理的。栈中存放的元素是CCAutoreleasePool对象的指针,存放该元素的容器栈是m_pReleasePoolStac,其中m_pCurReleasePool永远是指向栈顶。

现在我们的问题:

(1)我们的对象如场景对象,精灵对象等等,怎样与要存放的元素CCAutoreleasePool 相关联起来。

(2)容器栈是怎么定义的。

我们先来看看从整体来看看。

主要的类成员如下:


CCPoolManager::sharedPoolManager()->addObject(this);

把刚刚创建的场景类添加到CCPoolManager对象中 。注:CCPoolManager是单列。

找到CCPoolManager::addObject定义:


先获取当前释放内存池

如果当前自动释放内存池不为空,

则把场景对象存入自动释放内存池中。

现在我们来看看是怎么存放进去的。我们找到push函数:


原来是先new栈元素,并把该栈顶指针新创建的也就是pPool对象,

m_pReleasePoolStack->addObject(pPool);  

getCurReleasePool()->addObject(pObject);

获取到了栈顶指针,现在开始往栈顶元素中添加对象。


以上解决了问题(1)中的问题。

现在我们来解决问题(2),我们回到原来的代码

问题(2)才是核心内容。

还是看push()函数:

 CCAutoreleasePoolpPool = new CCAutoreleasePool(); 

找到构造函数的定义:


我们先看看CCArray的构造函数,


其中data数据类型的定义如下:

默认的容器大小为1

接着看initWithCapacity的定义:

ccArrayFree(data);首先释放内存。

data = ccArrayNew(capacity);

先申请了一个ccArray的结构体memory

后面在为结构体的数据成员开辟内存空间。

arr->arr =  (CCObject**)calloc(capacitysizeof(CCObject*));

大家可以去网上找带你资料了解下calloc函数的用法。

我的理解如下:

申请了capacity 个大小sizeof(CCObject*)的内存,并把返回的地址转换为(CCObject**)指针。

现在举例:capacity = 4. 注意:sizeof(CCObject*) = 4 

为了更好的理解我还是画一个图吧:

arr->arr地址0x120;


注:其实calloc会自动初始化内存。也就是为0.只是为了更形式的理解我才把数据写上

可以看出calloc申请的内存大小其实就是16字节。

但是要注意的是,objec1~object4都是指向CCObject对象的指针。

arr->num = 0;  //代表当前已经存放的对象个数。

arr->max = capacity;//最多能存放元素的个数。

现在我们知道了内存通过什么形式来存储对象的。

 m_pManagedObjectArray->init();

初始化容器。也就是上面讲得new内存。其实这里我也觉得奇怪,

在 m_pManagedObjectArray = new CCArray();其实已经初始化了内存,

我认为 m_pManagedObjectArray->init();这句代码是多余额,可以删掉。我删除了这行代码,运行没有问题。

现在应该清楚了栈元素的数据结构吧,其实就是ccArray:


现在来看看m_pReleasePoolStack数据成员:

CCArray*    m_pReleasePoolStack

也是一个动态数组类。

我们现在来理一理 ccArrayAppendObjectWithResize(dataobject);参数data到底是指哪个类的数据成员。


通过CCPoolManagerCCPoolManager::sharedPoolManager() 调用的都是单列。

从构造函数中可以看出,m_pReleasePoolStackm_pCurReleasePool生存方法一样,

只是作用不一样。

所以调用的ccArrayAppendObjectWithResize(dataobject);data是m_pReleasePoolStack成员的数据。Object才是m_pCurReleasePool对象。

现在我们把入栈的图画出来:

注: 容器大小为1.

备注:object = 0代表没有对象。

添加了一个元素进来。图如下:

                 

备注:这里只是为将要添加的对象,申请了一个栈元素的空间。

后面我就要填充Object = 0 的对象。

该函数就是在如果装满了,就开max = max *2的buf.

现在来看看这个push函数中的最后一句代码。

pPool->release();    

我们可以从CCObject的构造函数中看出

CCAutoreleasePoolpPool = new CCAutoreleasePool();       //ref = 1 即m_uReference = 1

在该函数 m_pReleasePoolStack->addObject(pPool);                   //ref = 2

会调用 object->retain(); 即m_uReference = 2

最后的栈结果如下:

m_pReleasePoolStack入栈后


所以内存管理,变动的只是Object = m_pCurReleasePool

如果要在添加一个元素如下图:

    m_pReleasePoolStack入栈后


后面继续,先休息下。写了一天了。

有问题欢迎大家提出。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值