原文地址:http://blog.csdn.net/a7833756/article/details/7628328
前言:c++内存机制,采用new关键字实例化的对象,必须在不使用的时候手动delete掉,否则new的时候开辟的内存就不能被回收,造成内存泄露。
我们来举个例子说明一下:
运行 结果,vld工具提示了存在内存泄露:
当加上delete操作后:
下面步入正题:
1、cocos2d-x 内存管理的方式,cocos2d-x采用引用计数的方式进行内存管理,当一个对象的引用计数为0的时候,就会被引擎自动delete掉。
所有cocos2d-x里面的类都继承ccobject类(应该是吧、),下面看ccobject类源码:
这里 m_uReference 就是引用计数,在对象构造的时候,m_uReference置为1
然后每次对对象进行retain操作,reference+1
每次对对象进行release操作,reference-1,如果reference在这次release之后变为0,那么delete掉它
2、以上是内存管理的基本原则,下面来讲引擎中是怎么对对象进行自动管理(autorelease)的。
我们以一个CCNode的生命历程为例,来讲一下自动管理的整个过程:
首先创建一个CCNode:
CCNode对象被new出来之后,立刻执行autorelease操作,我们来进行跟踪:
可以看到,首先将m_bManaged置为true,表示处于自动管理状态,然后加入自动管理池,继续跟踪:
getCurReleasePool() 返回一个 CCAutoreleasePool 对象指针,也就是一个自动释放池,那么我们先去看看这个自动释放池里面有什么:
首先就是一个ccobject数组,m_pManagedObjectArray , 这个数组放的就是接受自动释放的对象,也就是说,进行autorelease的对象,最终被放到它里面去了
那我们注意一下这里,m_pManagedObjectArray 是一个 CCMutableArray 对象,它的addobject()方法除了把一个对象放到这个array里面去,还做了什么呢,我们来看看源码:
大家应该看到了,进行了一次retain()操作,使得对象的引用+1,那么对象在被add到这个array里之后,引用应该为2(不考虑其他地方进行的retain),所以在此之后立刻进行了一次release(),使得这次add造成的引用取消,这样一来,对象从创建开始引用为1,到现在被放进自动释放池中后,引用依然为1,同时,被管理状态为true。
那么我再进行深入的分析一下
getCurReleasePool()->addObject(pObject);
里面的getCurReleasePool()方法,注意这个方法是 CCPoolManager 的方法:
那么我看到 CCPoolManager 类,顾名思义,我们也想得到它是对自动释放池进行管理的类,这是个全局变量,在main()函数执行之前由系统自动调用其默认构造方法进行实例化。下面进入这个类去看看里面有些什么:
我们发现了,里面有一个 CCAutoreleasePool 对象 m_pCurReleasePool, 看它名字, 可以理解为 当前自动释放池 ,然后有一个内存池的数组 m_pReleasePoolStack ,里面放的就是多个内存释放池了(我好像就看到一个进去了)。那么我们连上刚才的思路,进去看看push()函数,做了什么事情:
如代码所示,push()操作new了一个自动释放池对象,并且将它赋值给 当前自动释放池(m_pCurReleasePool),然后将这个new的自动释放池对象放到CCPoolManager 里面的 释放池数组中。注意过程中对其引用计数的控制,自动释放池本身也是继承ccobject的,也有自己的引用计数,受相同的内存管理方式。
那么到这里,一个对象的autorelease()过程就完成了。
那么我来做一个简单的总结:
首先 new 一个对象, 然后执行其autorelease()方法,接下来是得到CCPoolManager 对象(这是一个全局的对象),用它的getCurReleasePool获取 当前自动释放池对象,并将这个new的对象放入 当前自动释放池对象 里面的m_pManagedObjectArray数组中,修改其被管理状态 m_bManaged 为 true。执行完这个完整的操作之后,这个新new出来的对象的引用次数为1,被管理状态为true,并且被放在一个管理对象的数组中。
先理解自动释放池的添加过程,并且搞清楚对象被添加前后之间的变化,然后下一篇,来讲被自动管理的对象是如何被引擎自动删除的。