cocos2dx 里的使用引用计数的对象都是继承CCObject的。
引擎里大多数提供的类型是使用引用计数的。
可以手动release 和retain,分别是计数减和加
如果不想手动释放就调用autorelease,该对象会被放到CCPoolManager 内存管理池的当前的释放池里面(内存管理池里有内存池数组,最后创建的内存池就是当前的内存池)。
内存管理器是个单例(CCPoolManager::sharedPoolManager()),可以在程序结束时删除。
刚创建的对象(引用为1)添加到内存池管理器后,引用计数还是1(先加1后减1),会在当前帧渲染后删除,如果手动retain一次,引用计数就是2,当前帧过后引用计数减1就成了1,以后需要手动释放。
本文内容:
1、引用计数对象
2、内存池管理器
3、管理器的对象回收
(1)应用的消息循环
(2) 导演者的主循环
(3)回收内存管理器中的当前内存池
1、引用计数对象
在构造函数时为1 ,m_bManaged 的标记为false
CCObject::CCObject(void)
{
static unsigned int uObjectCount = 0;
m_uID = ++uObjectCount;
m_nLuaID = 0;
// when the object is created, the refrence count of it is 1
m_uReference = 1;
m_bManaged = false;//对于刚创建的CCObject对象,是不被释放池管理的
}
析构的时候,若是被管理的就由内存管理者移除
CCObject::~CCObject(void)
{
// if the object is managed, we should remove it
// from pool manager
if (m_bManaged)
{
CCPoolManager::sharedPoolManager()->removeObject(this);
}
// if the object is referenced by Lua engine, remove it
if (m_nLuaID)
{
CCScriptEngineManager::sharedManager()->getScriptEngine()->removeCCObjectByID(m_nLuaID);
}
}
函数release 和retain就是计数减和加
void CCObject::release(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
--m_uReference;
if (m_uReference == 0)
{
delete this;
}
}
void CCObject::retain(void)
{
CCAssert(m_uReference > 0, "reference count should greater than 0");
++m_uReference;
}
函数autorelease()就是把自己交由内存池管理者来管理
CCObject* CCObject::autorelease(void)
{
CCPoolManager::sharedPoolManager()->addObject(this);
m_bManaged = true;
return this;
}
2、内存池管理器
内存池管理者有一个释放池队列(数组形式的),操作如下
void CCPoolManager::addObject(CCObject* pObject)
{
getCurReleasePool()->addObject(pObject);
}
CCAutoreleasePool* CCPoolManager::getCurReleasePool()
{
if(!m_pCurReleasePool)
{
push();
}
CCAssert(m_pCurReleasePool, "current auto release pool should not be null");
return m_pCurReleasePool;
}
void CCPoolManager::push()
{
CCAutoreleasePool* pPool = new CCAutoreleasePool(); //ref = 1
m_pCurReleasePool = pPool;
m_pReleasePoolStack->addObject(pPool); //ref = 2
pPool->release(); //ref = 1
}
一个释放池里面有被管理的实体的列表(数组形式)
class CC_DLL CCAutoreleasePool : public CCObject
{
CCArray* m_pManagedObjectArray;
}
实体(CCObject)实际上是存放在m_pManagedObjectArray
内存管理者析构的时候就删除释放池里面的实体队列 以及 释放池 堆栈
CCPoolManager::~CCPoolManager()
{
finalize();
// we only release the last autorelease pool here
m_pCurReleasePool = 0;
m_pReleasePoolStack->removeObjectAtIndex(0);
CC_SAFE_DELETE(m_pReleasePoolStack);//删除释放池 堆栈
}
删除释放池里面的实体队列
void CCPoolManager::finalize()
{
if(m_pReleasePoolStack->count() > 0)
{
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pReleasePoolStack, pObj)
{
if(!pObj)
break;
CCAutoreleasePool* pPool = (CCAutoreleasePool*)pObj;
pPool->clear();//release 所有管理的引用计数对象
}
}
}
在内存池管理者构造函数里面初始化 释放池数组
CCPoolManager::CCPoolManager()
{
m_pReleasePoolStack = new CCArray();
m_pReleasePoolStack->init();//这里在是多写了的,CCArray默认构造函数里面就有init();
m_pCurReleasePool = 0;
}
CCArray::CCArray()
: data(NULL)
{
init();
}
释放池的内存数组初始化大小为1
bool CCArray::init()
{
return initWithCapacity(1);
}
CCArray::initWithCapacity(unsigned int capacity)
{
ccArrayFree(data);
data = ccArrayNew(capacity);
return true;
}
ccArray* ccArrayNew(unsigned int capacity)
{
if (capacity == 0)
capacity = 1;
ccArray *arr = (ccArray*)malloc( sizeof(ccArray) );
arr->num = 0;
arr->arr = (CCObject**)calloc(capacity, sizeof(CCObject*));
arr->max = capacity;
return arr;
}
其中ccArray* data;
ccArray 类型定义
typedef struct _ccArray {
unsigned int num, max;
CCObject** arr;
} ccArray;
3、管理器的对象回收
回收内存池管理者的当前内存池的引用计数对象
(1)应用的消息循环
int CCApplication::run()
{
......
while (1)
{
//没有消息才处理帧渲染(在导演者循环里的,画当前场景上的所有图形节点) ,和释放内存管理器的当前内存池的引用计数对象
if (! PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// Get current time tick.
QueryPerformanceCounter(&nNow);
// If it's the time to draw next frame, draw it, else sleep a while.
if (nNow.QuadPart - nLast.QuadPart > m_nAnimationInterval.QuadPart)
{
nLast.QuadPart = nNow.QuadPart;
CCDirector::sharedDirector()->mainLoop();
}
else
{
Sleep(0);
}
continue;
}
//有事件则优先处理程序窗口事件
if (WM_QUIT == msg.message)
{
// Quit message loop.
break;
}
// Deal with windows message.
if (! m_hAccelTable || ! TranslateAccelerator(msg.hwnd, m_hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
(2)导演者的主循环
CCDisplayLinkDirector::mainLoop(void)
{
if (m_bPurgeDirecotorInNextLoop)
{
m_bPurgeDirecotorInNextLoop = false;
purgeDirector();
}
else if (! m_bInvalid)
{
drawScene(); //渲染当前场景
// release the objects
CCPoolManager::sharedPoolManager()->pop(); //释放当前内存池的引用计数对象
}
}
(3)回收内存管理器中的当前内存池
void CCPoolManager::pop()
{
if (! m_pCurReleasePool)
{
return;
}
int nCount = m_pReleasePoolStack->count();
m_pCurReleasePool->clear();//释放当前内存池的引用计数对象
if(nCount > 1)
{
//去掉最后一个内存池
m_pReleasePoolStack->removeObjectAtIndex(nCount-1);
//取出倒数最后一个内存池作为当前的内存池
m_pCurReleasePool = (CCAutoreleasePool*)m_pReleasePoolStack->objectAtIndex(nCount - 2);
}
}
3、管理器的对象回收
(1)在导演者的主循环里回收所有
3、管理器的对象回收
回收内存池管理者的当前内存池的引用计数对象
(1)应用的消息循环