码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-10-09 15:09:04      阅读:181      评论:0      收藏:0      [点我收藏+]

标签:blog   http   os   ar   strong   数据   sp   art   on   

最近在看内存管理的源码,发现这篇文章讲的不错,思路很清晰,故转载收藏。

原地址:http://blog.csdn.net/a7833756/article/details/7628328

1、cocos2d-x 内存管理的方式,cocos2d-x采用引用计数的方式进行内存管理,当一个对象的引用计数为0的时候,就会被引擎自动delete掉。

所有cocos2d-x里面的类都继承ccobject类(应该是吧、),下面看ccobject类源码:

bubuko.com,布布扣

bubuko.com,布布扣

这里 m_uReference 就是引用计数,在对象构造的时候,m_uReference置为1

bubuko.com,布布扣

bubuko.com,布布扣

然后每次对对象进行retain操作,reference+1

bubuko.com,布布扣

    bubuko.com,布布扣

每次对对象进行release操作,reference-1,如果reference在这次release之后变为0,那么delete掉它

bubuko.com,布布扣

bubuko.com,布布扣

2、以上是内存管理的基本原则,下面来讲引擎中是怎么对对象进行自动管理(autorelease)的。

我们以一个CCNode的生命历程为例,来讲一下自动管理的整个过程:

首先创建一个CCNode:

 bubuko.com,布布扣bubuko.com,布布扣

CCNode对象被new出来之后,立刻执行autorelease操作,我们来进行跟踪:bubuko.com,布布扣

bubuko.com,布布扣

可以看到,首先将m_bManaged置为true,表示处于自动管理状态,然后加入自动管理池,继续跟踪:

bubuko.com,布布扣

bubuko.com,布布扣

getCurReleasePool() 返回一个 CCAutoreleasePool 对象指针,也就是一个自动释放池,那么我们先去看看这个自动释放池里面有什么:

bubuko.com,布布扣

bubuko.com,布布扣

首先就是一个ccobject数组,m_pManagedObjectArray , 这个数组放的就是接受自动释放的对象,也就是说,进行autorelease的对象,最终被放到它里面去了bubuko.com,布布扣bubuko.com,布布扣

那我们注意一下这里,m_pManagedObjectArray 是一个 CCMutableArray 对象,它的addobject()方法除了把一个对象放到这个array里面去,还做了什么呢,我们来看看源码:

bubuko.com,布布扣

bubuko.com,布布扣

大家应该看到了,进行了一次retain()操作,使得对象的引用+1,那么对象在被add到这个array里之后,引用应该为2(不考虑其他地方进行的retain),所以在此之后立刻进行了一次release(),使得这次add造成的引用取消,这样一来,对象从创建开始引用为1,到现在被放进自动释放池中后,引用依然为1,同时,被管理状态为true。

那么我再进行深入的分析一下

  getCurReleasePool()->addObject(pObject);bubuko.com,布布扣

  里面的getCurReleasePool()方法,注意这个方法是 CCPoolManager 的方法:

bubuko.com,布布扣

bubuko.com,布布扣

那么我看到 CCPoolManager 类,顾名思义,我们也想得到它是对自动释放池进行管理的类,这是个全局变量,在main()函数执行之前由系统自动调用其默认构造方法进行实例化。下面进入这个类去看看里面有些什么:

 bubuko.com,布布扣bubuko.com,布布扣

 我们发现了,里面有一个 CCAutoreleasePool 对象 m_pCurReleasePool, 看它名字, 可以理解为 当前自动释放池 ,然后有一个内存池的数组 m_pReleasePoolStack ,里面放的就是多个内存释放池了(我好像就看到一个进去了)。那么我们连上刚才的思路,进去看看push()函数,做了什么事情:

 bubuko.com,布布扣bubuko.com,布布扣

如代码所示,push()操作new了一个自动释放池对象,并且将它赋值给 当前自动释放池(m_pCurReleasePool),然后将这个new的自动释放池对象放到CCPoolManager 里面的 释放池数组中。注意过程中对其引用计数的控制,自动释放池本身也是继承ccobject的,也有自己的引用计数,受相同的内存管理方式。

那么到这里,一个对象的autorelease()过程就完成了。

 

那么我来做一个简单的总结:

首先 new 一个对象, 然后执行其autorelease()方法,接下来是得到CCPoolManager 对象(这是一个全局的对象),用它的getCurReleasePool获取 当前自动释放池对象,并将这个new的对象放入 当前自动释放池对象 里面的m_pManagedObjectArray数组中,修改其被管理状态 m_bManaged 为 true。执行完这个完整的操作之后,这个新new出来的对象的引用次数为1,被管理状态为true,并且被放在一个管理对象的数组中。

-----------------------------------------------------------------------------------------

一个被自动管理的对象从new出来之后到被放到autoreleasepool那么接下来,对象是如何被引擎自动delete掉的呢?首先我们要知道,cocos2d-x的引擎线程是单线程的,它不停的调用voidCCDisplayLinkDirector::mainLoop(void)来绘制当前的Scene ,同时对一些自动释放的对象进行管理。我们先到一个cocos2d-x项目的main()函数里面:

bubuko.com,布布扣

 

这里调用了一个run()方法,我们跟踪进去:

bubuko.com,布布扣

 

 

Run方法有个while(1)循环,不断的调用mainLoop(void)方法,来完成界面渲染和对象释放,我们进mainLoop():

bubuko.com,布布扣

 

于是我们看到了引擎对自动管理的对象进行释放的操作。它调用的,是CCPoolManager的pop()方法,我们去看看这个pop()方法:

bubuko.com,布布扣

 

如代码里面所示,m_pReleasePoolStack就是之前提到的当前内存池,也就是内存池管理者里面那个内存池堆栈的栈顶的那个内存池,对其进行clear()操作,记住,在clear()之前,被放置在自动管理池内的对象的引用次数都是为1的(依然只考虑对象被new出来之后马上autorelease()操作并且在其他地方不进行retain()),那么进行clear()操作时:

bubuko.com,布布扣

 

 

CCAutoreleasePool会做这样两件事情,首先会把池中所有对象的被管理状态置为false,表示对象已经不再处于自动管理状态,然后清除管理池中所有的对象引用:

bubuko.com,布布扣

 

在这一过程中,会调用每个对象的release()方法,这样,我们算一下,之前对象的引用次数为1,那么在这里进行一次release之后,引用为0,就会执行delete操作,这样一来,这个被管理的对象就被成功释放掉了。

下面我们来写个小demo验证一下这个过程:

New一个对象:

bubuko.com,布布扣

 

 

s的引用次数为1,被管理状态为false:

bubuko.com,布布扣

 

对其进行autorelease()

bubuko.com,布布扣

 

 

s的引用依然为1,被管理状态为true:

bubuko.com,布布扣

 

然后进行一次retain()操作:

bubuko.com,布布扣

 

引用变为2

bubuko.com,布布扣

 

 

接下来刷下一帧,刷完后我们再看o对象,发现其被管理状态变为false,引用变成1了,这说明如果我们之前没有手动执行过retain(),这个对象已经被引擎给回收掉了。

bubuko.com,布布扣

 

这样一来,验证了引擎的自动回收机制,我们可以在retain()后面release()一次,来看看对象o被delete后的状态:

bubuko.com,布布扣

 

 

发现其内部的数据都变成随机数值了,也就是对象已经被清除了。

 

最后我来做个简单的总结

Cocos2d-x中,采用引用计数的方式进行内存管理,谁需要引用这个对象,就对其retain()一次,同时在不需要它的时候,就要对其进行release()操作,这一点在引擎很多地方有示例,例如CCNode进行addchild()操作时,会对child进行retain()表示对其引用:

bubuko.com,布布扣

而在removeChild()的时候会对其进行release()操作

bubuko.com,布布扣

 

第二点是对象的autorelease()操作,该操作的效果是对象在当前这一帧被new出来之后,在下一帧之前没有被执行retain()(例如被add到某个CCMutableArray,或者被一个父Node作为子节点,也可以是我们手动retain()),那么这个对象在下一帧就会被引擎给delete掉,那么有时候出现的空指针错误,可能就来源于此。还有的时候,是在自己手动retain()后放入autorelease池,这样引擎只能将对象的引用减一,而不能delete掉,从而造成内存泄露。

 

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

标签:blog   http   os   ar   strong   数据   sp   art   on   

原文地址:http://www.cnblogs.com/cxiaojia/p/4013056.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!