对Cocos2dX的内存管理不了解的人会有这样的疑惑,Cocos2dX的自动内存池是干什么的?当调用一个对象的autorelease后,该对象就被加入到自动内存池中。那是否意味着我们可以不用再去对该对象进行retain,release了呢?
答案是错的。自动内存池只作用于那些”创建期“的对象,也就是说对于那些用create函数创建出来的对象,实际上是调用了autorelease,而autorelease会把该对象加入到自动内存池中,而在用create函数创建了对象后的那一帧,当前自动内存池中的所有对象都会被release一次,然后清空该自动内存池。下面是分析过程:
一.create函数的内幕
使用create函数创建对象实际上会调用autorelease,而autorelease又会将该对象加入到当前自动内存池中:
- #define CREATE_FUNC(__TYPE__) \
- static __TYPE__* create() \
- { \
- __TYPE__ *pRet = new(std::nothrow) __TYPE__(); \
- if (pRet && pRet->init()) \
- { \
- pRet->autorelease(); \
- return pRet; \
- } \
- else \
- { \
- delete pRet; \
- pRet = NULL; \
- return NULL; \
- } \
- }
- Ref* Ref::autorelease()
- {
- PoolManager::getInstance()->getCurrentPool()->addObject(this);
- return this;
- }
二.为什么会有自动内存池
我们来看下每帧中自动内存池会执行什么:
- int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
- {
- UNREFERENCED_PARAMETER(hPrevInstance);
- UNREFERENCED_PARAMETER(lpCmdLine);
- // create the application instance
- AppDelegate app;
- return Application::getInstance()->run();
- }
- int Application::run()
- {
- PVRFrameEnableControlWindow(false);
- // Main message loop:
- LARGE_INTEGER nLast;
- LARGE_INTEGER nNow;
- QueryPerformanceCounter(&nLast);
- initGLContextAttrs();
- // Initialize instance and cocos2d.
- if (!applicationDidFinishLaunching())
- {
- return 1;
- }
- auto director = Director::getInstance();
- auto glview = director->getOpenGLView();
- // Retain glview to avoid glview being released in the while loop
- glview->retain();
- while(!glview->windowShouldClose())
- {
- QueryPerformanceCounter(&nNow);
- if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
- {
- nLast.QuadPart = nNow.QuadPart - (nNow.QuadPart % _animationInterval.QuadPart);
- director->mainLoop();
- glview->pollEvents();
- }
- else
- {
- Sleep(1);
- }
- }
- // Director should still do a cleanup if the window was closed manually.
- if (glview->isOpenGLReady())
- {
- director->end();
- director->mainLoop();
- director = nullptr;
- }
- glview->release();
- return 0;
- }
run函数中有这么一句,director->mainLoop(),跟踪进去:
- void DisplayLinkDirector::mainLoop()
- {
- if (_purgeDirectorInNextLoop)
- {
- _purgeDirectorInNextLoop = false;
- purgeDirector();
- }
- else if (_restartDirectorInNextLoop)
- {
- _restartDirectorInNextLoop = false;
- restartDirector();
- }
- else if (! _invalid)
- {
- drawScene();
- // release the objects
- PoolManager::getInstance()->getCurrentPool()->clear();
- }
- }
- void AutoreleasePool::clear()
- {
- #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
- _isClearing = true;
- #endif
- std::vector<Ref*> releasings;
- releasings.swap(_managedObjectArray);
- for (const auto &obj : releasings)
- {
- obj->release();
- }
- #if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
- _isClearing = false;
- #endif
- }
调用releasings.swap(_managedObjectArray)后当前自动内存池中就被清空了。
创建一个对象时,该对象的引用计数被初始化为1,如果我们没有对该对象进行retain操作,或者没有使用它(也就是没有其它对象引用它),那么该对象的引用计数则为1,调用上面的代码后,该对象的引用计数变为0,之后便不复存在。
- for (const auto &obj : releasings)
- {
- obj->release();
- }