因为cocos2dx我们的使用c++写的,所以内存管理就是一个绕只是去的坎,这个你不懂内存仅仅懂业务逻辑的话,还玩什么c++,今天看了半天这个东西,事实上本质上是理解的,可是就是有一个过不去的坎,最终在今天晚上搞定了,于是想给大家分享一下。争取我把网上的优质的精华在经过自己的理解。分享给大家啊。

内存的管理我们一般有两种方式,引用计数和垃圾回收。

我们cocos2dx採用的就是引用计数,而非常火的java就是垃圾回收。引用计数,垃圾回收具体解释:

引用计数:通过给每一个对象维护一个引用计数器,记录该对象当前被引用的次数。

当对象添加一次引用时,计数器加一:而失去一次引用时,计数器减一;当计数为0时。标志着该对象的生命周期结束。自己主动触发对象的回收释放。

引用计数攻克了对象的生命周期管理问题,但堆碎片化的和管理繁琐的问题仍然存在。

     垃圾回收:他通过引入一种自己主动的内存回收期,试图将程序猿从复杂的内存管理任务中全然解放出来。他会自己主动跟踪每个个对象的全部引用,以便找到正在使用的对象,然后是房企与不再须要的对象。垃圾回收期一般是作为一个单独的低级别的线程执行的,在不可预知的情况下对内存堆中已经死亡的或者长时间没有使用过的对象进行清除和回收 。

我们着重的说关于引用计数,他的原理就是我们引用一个对象,就让对象的引用计数加一,失去一个引用一个对象就让引用计数减一。在cocos2dx中的方法就是retain和release,我们看CCObject。在CCObject里面有一个属性m_uReference就是引用计数的。

CCObject::CCObject(void)<span style="white-space:pre">	</span>
: m_nLuaID(0)
, m_uReference(1) // when the object is created, the reference count of it is 1注意这里,默认这个m_uReference是1的
, m_uAutoReleaseCount(0)
{
static unsigned int uObjectCount = 0; m_uID = ++uObjectCount;
}
void CCObject::retain(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0"); ++m_uReference;
}

retain方法,每次将m_uReference加一

void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference; if (m_uReference == 0)
{
delete this;
}
}

release每次将m_uReference减一,而且假设为0的话就delete掉。

假设我们手动管理,利用上面的方法就能够了。

可是我们主要说自己主动管理,自己主动管理事实上就是你仅仅管用即可了。关于释放的问题我们统一交给Cocos2dx引擎来释放,无需我们手动调用release

一般我们的类中会有一个create方法。这种方法大概是这样子的

MyScene * MyScene::create()
{
MyScene *pRet = new MyScene;
if (pRet && pRet->init())
{
pRet->autorelease();<span style="white-space:pre"> </span>//注意这里,在这个时候我们就将这个对象交给了引擎了,我们就无需再次手动释放,等待引擎自己释放即可了
return pRet;
}
else
{
CC_SAFE_DELETE(pRet);
}
return NULL;
}

有些人会问了。你简简单单的由于这么一句话就不释放了,就交给引擎了,你是怎么实现的。这玩意儿靠谱么,别怕,我们进入方法看看

CCObject* CCObject::autorelease(void)
{
CCPoolManager::sharedPoolManager()->addObject(this); //我们再次进去,见以下方法
return this;
} void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject); //我们再次进去。见以下方法
} void CCAutoreleasePool::addObject(CCObject* pObject)
{
m_pManagedObjectArray->addObject(pObject); //这里假设我们继续往下走,那么我们终究会找到一个pObject.retain的方法的, CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1");
++(pObject->m_uAutoReleaseCount);
pObject->release(); // no ref count, in this case autorelease pool added.
}

首先我们要说明CCAutoreleasePool叫做自己主动释放池,在CCPoolManager(自己主动释放池管理类)类里面我们有个成员变量 CCArray * m_pReleasePoolStack;这个是自己主动释放池栈,里面存放CCAutoreleasePool的实例。

CCAutoreleasePool内部有一个CCArray * m_pManagedObjectArray,这个是他内部的一个对象数组。

大体上他们的关系就是如此。我们每次自己主动托管对象以后,就会加到这个内存释放池里面,你可能会问了,这玩意儿我们不释放,那什么时候释放呢,答案就是每一次帧循环就释放一次。而且又一次创建一个自己主动释放池。

我们看mainLoop代码

void CCPoolManager::pop()
{
if (! m_pCurReleasePool)
{
return;
} int nCount = m_pReleasePoolStack->count(); m_pCurReleasePool->clear(); //大家注意看这里了。这个意思不就是内存池清空吗,我们倒是要看看他怎么清空 if(nCount > 1)
{
m_pReleasePoolStack->removeObjectAtIndex(nCount-1); // if(nCount > 1)
// {
// m_pCurReleasePool = m_pReleasePoolStack->objectAtIndex(nCount - 2);
// return;
// }
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);//这里我们在新的一帧里面又一次的初始化了这个内存池
} /*m_pCurReleasePool = NULL;*/
} void CCAutoreleasePool::clear()
{
if(m_pManagedObjectArray->count() > 0)
{
//CCAutoreleasePool* pReleasePool;
#ifdef _DEBUG
int nIndex = m_pManagedObjectArray->count() - 1;
#endif CCObject* pObj = NULL;
CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj)
{
if(!pObj)
break; --(pObj->m_uAutoReleaseCount);//这里的意思就是自己主动管理的标志变为0了
//(*it)->release();
//delete (*it);
#ifdef _DEBUG
nIndex--;
#endif
} m_pManagedObjectArray->removeAllObjects();
}
}

大概就是这个样子的,我们想象假设我们仅仅是简简单单的create了一个经理,并没有把它挂到渲染树上面,我们的引用计数肯定是1啊,然后再经过自己主动释放池的减减。就会被释放了啊。

第一种情况:

CCScene *pscene = CCScene::create();   //引用计数为1,在内部默认autorelease了

。经过了帧循环的清栈了,引用减一,pscene就被干掉了。

另外一种情况:

CCScene *pscene = CCScene::create();   //引用计数为1。在内部默认autorelease了

addChild(pscene);//引用计数为2。

经过了帧循环的清栈,引用减一。引用计数就变为1。而且下次就不会再这个自己主动释放池里了。所以这个精灵就能够一直在渲染树上了,我们什么时候想删他。兴许要想释放这个“精灵”,我们还是须要手工调用release。或再调用其autorelease方法。

我小做总结一下,这个嘛就是,我们吧一个CCObject运行了autorelease方法,自己主动释放池就会默认在下一帧循环開始的时候给我们-1,由于之前的我们托管了。理论上,假设引用计数减一之后为零了,就是本身应该我们释放的,可是我们托管给了引擎,引擎就会义不容辞的帮我们把它释放掉。

假设我们不仅自己创建了,还把它加到了渲染树上。表示这个精灵我们要继续用,自己主动释放池就会在将引用计数减一后为一,引擎就会知道你在creat这个精灵之后你还在用,我就无论了,让他继续活着,我还是要清理自己主动释放池。由于我要为这次的帧循环做准备。

不知不觉都写到这个点了。本来还是想再说一点,早点刷牙睡觉吧,今天这个真的是搞得我天昏地暗。日月无光,道理我懂。就是没有把思想转换过来,開始没有弄懂为什么就这么释放了,后来知道了。这个本来应该我们干。可是有时候这些是注冊函数,中断函数等等,我们不知道什么时候干, 所以就要交给引擎来干,由于他知道怎么干。

刷牙,睡觉,各位晚安吧。。。。。。。

201215-03-19---cocos2dx内存管理--具体解释的更多相关文章

  1. cocos2dx内存管理的一些看法

    今年年初进入一家游戏公司,正式开始游戏引擎的学习,之前的ios学习,对现在的游戏引擎学习还是有很大的帮助的,虽然使用c++,但却能时刻感受到ios框架对于cocos2dx的巨大影响. 由于之前一直使用 ...

  2. cocos2d-x内存管理

    Cocos2d-x内存管理 老师让我给班上同学讲讲cocos2d-x的内存管理,时间也不多,于是看了看源码,写了个提纲和大概思想 一.   为什么需要内存管理 1. new和delete 2. 堆上申 ...

  3. 2、COCOS2D-X内存管理机制

    在C++中.动态内存分配是一把双刃剑,一方面,直接訪问内存地址提高了应用程序的性能,与使用内存的灵活性.还有一方面.因为程序没有正确地分配与释放造成的比如野指针,反复释放,内存泄漏等问题又严重影响着应 ...

  4. cocos2dx内存管理机制

    参考以下两篇文章 http://blog.csdn.net/ring0hx/article/details/7946397 http://blog.csdn.net/whuancai/article/ ...

  5. Cocos2d-X内存管理研究<一>

    http://hi.baidu.com/tzkt623/item/651ca7d7a0aff6e055347f67        半夜没事干,研究内核,作为我cocos2d-x的第一篇教程.cocos ...

  6. Cocos2d-x内存管理解说在ios开发中

    使用过 Cocos2d-x 都知道,其中有一套自己实现的内存管理机制,不同于一般 C++ 的编写常规,而在使用前,了解其原理是有必要的,网上已经有很多对内部实现详细解说的文章.而对于使用者而言,并不需 ...

  7. cocos2d-x内存管理(见解)

    cocos2d-x 延续了cocos2d 和OC的引用计数的内存管理机制! 下面我们来看看CCDriectro类 CCPoolManager::sharedPoolManager()->push ...

  8. cocos2d-x 内存管理浅析

    Cocos2d-x用create创建对象, 这个方法已经被引擎封装成一个宏定义了:CREATE_FUNC, 下面是这个宏定义的实现: #define CREATE_FUNC(__TYPE__) \   ...

  9. cocos2dx 内存管理的理解

    关于引擎内存管理的细节,网上有大量的详解,这里概括一下: cocos2d-x 的世界是基于 CCObject 类构建的,所以内存管理的本质就是管理一个个 CCObject. //CCObject 内部 ...

随机推荐

  1. iostat查看io情况(监控Linux的8种方式)

    查看TPS和吞吐量信息[root@controller ~]#iostat -d -k 1 10Device:         tps    kB_read/s    kB_wrtn/s    kB_ ...

  2. VC socket Connect 超时时间设置

    设置connect超时很简单,CSDN上也有人提到过使用select,但却没有一个令人满意与完整的答案.偶所讲的也正是select函数,此函数集成在winsock1.1中,简单点讲,"作用使 ...

  3. VB与报表的交互

    还接着上次说.在上个博客中已经说到建立好表的步骤了,接下来就是怎么使表与vb连接. 先看一下代码. Option Explicit Dim WithEvents Report As grproLibC ...

  4. uva 10692 - Huge Mods(数论)

    题目链接:uva 10692 - Huge Mods 题目大意:给出一个数的次方形式,就它模掉M的值. 解题思路:依据剩余系的性质,最后一定是行成周期的,所以就有ab=abmod(phi[M])+ph ...

  5. HDU4549 M斐波那契数

    M斐波那契数列 题目分析: M斐波那契数列F[n]是一种整数数列,它的定义例如以下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2] ( n > 1 ) 如今给 ...

  6. VIM 用正则表达式

    VIM 用正则表达式 批量替换文本,多行删除,复制,移动 在VIM中 用正则表达式 批量替换文本,多行删除,复制,移动 :n1,n2 m n3     移动n1-n2行(包括n1,n2)到n3行之下: ...

  7. SetBkMode可设置文字背景色:TRANSPARENT或OPAQUE

    感受一下区别: procedure TForm1.Timer2Timer(Sender: TObject); var cvs: TCanvas; Rect: TRect; Str: string; b ...

  8. vc 制作图片资源dll

    方法一: 使用纯WIN32 DLL方法封装纯资源第一步,通过VS2005建立WIN32 DLL 空工程第二步,设置配置属性->链接器->高级->无入口点(是/NOENTRY)设置配置 ...

  9. perl 异步请求和JS对比

    perl 异步和js对比: /js************** $(function(){ function isPhone(str){ var regex = /[0-9]{11,11}/; ret ...

  10. 8086 CPU 寻址方式

    8086 CPU 寻址方式灵活.有以下几种 idata 表示常量 1.   [ idata ] 用一个常量来表示地址,可用于直接定位内存单元,但是在 MASM中要显实在的说明 ds 段寄存器, 比如 ...