201215-03-19---cocos2dx内存管理--具体解释

因为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这个精灵之后你还在用,我就无论了,让他继续活着,我还是要清理自己主动释放池。由于我要为这次的帧循环做准备。

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

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

时间: 2025-01-15 02:46:32

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

cocos2dx 内存管理

cocos2dx的内存管理移植自Objective-C, 对于没有接触过OC的C++开发人员来说是挺迷惑的.不深入理解内存管理是无法写出好的C++程序的,我用OC和cocos2dx也有一段时间了,在此总结一下,希望对想用cocos2dx开发游戏的朋友有所帮助. C++的动态内存管理一般建议遵循谁申请谁释放的原则,即谁通过new操作符创建了对象,谁就负责通过delete来释放对象.如果对象的生命周期在一个函数内,这很容易做到,在函数返回前delete就行了.但一般我们在函数中new出来的对象的生命

cocos2dx内存管理

cocos2dx基于引用计数管理内存,所有继承自CCObject的对象都将获得引用计数的能力,可通过调用retain成员函数用于引用计数值,调用release减少引用计数值,当计数值减为0时销毁对象. cocos2dx的对象管理是树形结构的,可通过调用父亲节点的addChild成员函数将一个子节点对象添加到父节点中,当子节点被添加到父亲节点中,子节点的引用计数值加1,如果通过removeChild将子节点从父节点中移除子节点的引用计数值减1.当父节点被销毁时,会遍历其所有的子节点,将其子节点的引

cocos2d-x 源码分析 : Ref (CCObject) 源码分析 cocos2d-x内存管理策略

源码版本来自3.x,转载请注明 cocos2d-x 源码分析总目录: http://blog.csdn.net/u011225840/article/details/31743129 1.Ref,AutoreleasePool,PoolManager Ref中包含了一个叫referenceCount的引用计数,当一个Ref类的变量被new的时候,其referenceCount的引用计数被置为1. 其中有三个重要的操作,retain,release,autorelease,下面源码分析时会详细说明

Cocos2d-x内存管理

Cocos2d-x内存管理浅解 1.首先我们知道内存管理分为c++自身管理机制以及Cocos2d-x内存管理机制.在c++中,内存分为堆区.栈区.静态存储区(全局存储区).常量存储区.自由存储区. 主要先说一下堆区和栈区.堆区主要由new和malloc分配,new与delete,malloc与free成对出现,保证内存的分配与回收.堆内存分配地址是逐渐增大的,这一点与栈区相反,我们都知道栈是先进后出,所以栈的存储方向是内存地址逐渐减小的.栈中的内存也是系统自动回收的,这个我们不需要考虑自己管理内

帝国塔防2充值界面闪退BUG修复总结(cocos2dx内存管理机制)

游戏充值界面老是闪断,debug调试断点总是断在比较深的位置,也看不出哪里出错. 后来有一次断点断在了程序创建一个提示图片的地方,于是检查代码发现了问题. 修改之前的错误代码: 1.创建提示的代码: m_loading = new NetLoading(this, callfunc_selector(IapShopLayer::downingUpdate)); // m_loading 引用计数为1 m_loading->setPosition(ccp(1139/2.0f, 640.0f/2.0

2、COCOS2D-X内存管理机制

在C++中,动态内存分配是一把双刃剑,一方面,直接访问内存地址提高了应用程序的性能,与使用内存的灵活性:另一方面,由于程序没有正确地分配与释放造成的例如野指针,重复释放,内存泄漏等问题又严重影响着应用程序的稳定性. 人们尝试着不同的方案去避免这个问题,比较常用的如智能指针,自动垃圾回收等,这些要么影响了应用程序的性能,要么仍然需要依赖于开发者注意一些规则,要么给开发者带来了另外一些很丑陋的用法(实际上笔者很不喜欢智能指针).因此,优秀的C++内存管理方案需要兼顾性能,易用性,所以到目前为止C++

cocos2d-x内存管理机制解析(转载)

最近在看内存管理的源码,发现这篇文章讲的不错,思路很清晰,故转载收藏. 原地址:http://blog.csdn.net/a7833756/article/details/7628328 1.cocos2d-x 内存管理的方式,cocos2d-x采用引用计数的方式进行内存管理,当一个对象的引用计数为0的时候,就会被引擎自动delete掉. 所有cocos2d-x里面的类都继承ccobject类(应该是吧.),下面看ccobject类源码: 这里 m_uReference 就是引用计数,在对象构造

记录关于cocos2dx内存管理机制可能崩溃的一个坑

大年初一写代码,纪念一下:) cocos2dx,内存管理方式如下: 所有Ref继承而来的类,皆放入AutoreleasePool,每一帧释放一次,如果引用计数为0,则delete. 因此,Ref在每帧的工作,就是先ref+1,后ref-1,让它ref-1的是AutoreleasePool,而让它ref+1的就各有方式了.最常见的就是CCNode,每帧为子节点retain的方式. 一般这是不会有问题的.如果你有需求在类中保存一个Ref对象,而它并非一个子节点,如RenderTexture,则必须记

cocos2dx 内存管理的理解

关于引擎内存管理的细节,网上有大量的详解,这里概括一下: cocos2d-x 的世界是基于 CCObject 类构建的,所以内存管理的本质就是管理一个个 CCObject. //CCObject 内部维护着一个引用计数,引用计数为 0 就自动释放 unsigned int m_uReference; //管理内存的实质就是管理这些 “引用计数” 了,使用 retain 和 release 方法对引用计数进行操作 void release(void);//引用计数:--m_uReference v