2dx引擎中的對象內存管理模型,很簡單就是一個對象池+引用計數,本着學好2dx的好奇心,先這裏開走吧,緊接上面兩節,首先咱們看一個編碼場景代碼: java
hello word : node
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" class HelloWorld : public cocos2d::CCLayer { public: // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::CCScene* scene(); // a selector callback void menuCloseCallback(CCObject* pSender); // implement the "static node()" method manually CREATE_FUNC(HelloWorld); }; #endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h" USING_NS_CC; CCScene* HelloWorld::scene() { // 'scene' is an autorelease object CCScene *scene = CCScene::create(); // 'layer' is an autorelease object HelloWorld *layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); ///////////////////////////// // 2. add a menu item with "X" image, which is clicked to quit the program // you may modify it. // add a "close" icon to exit the progress. it's an autorelease object CCMenuItemImage *pCloseItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::menuCloseCallback)); pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 , origin.y + pCloseItem->getContentSize().height/2)); // create menu, it's an autorelease object CCMenu* pMenu = CCMenu::create(pCloseItem, NULL); pMenu->setPosition(CCPointZero); this->addChild(pMenu, 1); ///////////////////////////// // 3. add your codes below... // add a label shows "Hello World" // create and initialize a label CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24); // position the label on the center of the screen pLabel->setPosition(ccp(origin.x + visibleSize.width/2, origin.y + visibleSize.height - pLabel->getContentSize().height)); // add the label as a child to this layer this->addChild(pLabel, 1); // add "HelloWorld" splash screen" CCSprite* pSprite = CCSprite::create("HelloWorld.png"); // position the sprite on the center of the screen pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer this->addChild(pSprite, 0); return true; } //close application void HelloWorld::menuCloseCallback(CCObject* pSender) { CCDirector::sharedDirector()->end(); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif }
代碼片斷中有一個 CREATE_FUNC(HelloWorld); HelloWorld *layer = HelloWorld::create(); 程序員
跟進看到,其實建立這個層的方法就是定義的CREATE_FUNC(xx);繼續追蹤,能夠看到,他建立這個層,同時會調用初始化inti()方法--準備layer基礎數據,也就是java上見的多的多態,這不是重點,他調用了,autorelease(),也就是咱們對象內存模型中的自動管理方法,這裏我先直接總結下,對象在建立的過程當中,建立以後,調用autorelease(),就會被添加到對象池中自動維護計數,當計數未0(在每一幀結束後),或者在析構中調用銷燬,那麼就將會衝對象池中移除;在看一個例子:CCArray *test=CCArray::create();test->retain(); 數組
這樣纔是纔會建立成功(額排除其餘異常);當咱們建立這個對象的時候,create()在返回這個對象的同時會將對象自動autorelease();因此你必須還得引用計數+1;爲何? 緩存
由於autorelease()將對象添加到對象池中,會自動release(),引用計算--1;默認引用計數爲1,當對象建立的時候,因此知道爲何會建立失敗了吧 若是標記對象被引用;固然你本身建立的對象就要這樣處理,若是是2dx的捏?那就直接穿件建立autorelease(),內存對象池會自動處理的; app
接下來直接看內存模型+引用計數,內存對象緩存是用的CCArray;具體看下面代碼片斷,該有的註解都有了: iphone
先是2dx中:object,java中全部對象的根接點,這裏你能夠這樣「理解」: 函數
/**************************************************************************** Copyright (c) 2010 cocos2d-x.org http://www.cocos2d-x.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #ifndef __CCOBJECT_H__ #define __CCOBJECT_H__ #include "CCDataVisitor.h" #ifdef EMSCRIPTEN #include <GLES2/gl2.h> #endif // EMSCRIPTEN NS_CC_BEGIN /** * @addtogroup base_nodes * @{ */ class CCZone; class CCObject; class CCNode; class CCEvent; class CC_DLL CCCopying { public: virtual CCObject* copyWithZone(CCZone* pZone); }; //對象繼承CCobject 均可以引用自動釋放池對象(引用計數+釋放池管理類) //根據開發的內容來劃分池對象,譬如一個場景建立一個自動釋放池,遊戲中場景切換時,釋放緩衝區最好時間 //引擎基類 class CC_DLL CCObject : public CCCopying { public: // 對象ID unsigned int m_uID; // Lua reference id int m_nLuaID; protected: // 計數對象 unsigned int m_uReference; // count of autorelease 計數自動釋放對象 unsigned int m_uAutoReleaseCount; public: CCObject(void); virtual ~CCObject(void); void release(void); void retain(void); CCObject* autorelease(void); CCObject* copy(void); bool isSingleReference(void) const; unsigned int retainCount(void) const; virtual bool isEqual(const CCObject* pObject); virtual void acceptVisitor(CCDataVisitor &visitor); virtual void update(float dt) {CC_UNUSED_PARAM(dt);}; //自動釋放池 friend class CCAutoreleasePool; }; typedef void (CCObject::*SEL_SCHEDULE)(float); typedef void (CCObject::*SEL_CallFunc)(); typedef void (CCObject::*SEL_CallFuncN)(CCNode*); typedef void (CCObject::*SEL_CallFuncND)(CCNode*, void*); typedef void (CCObject::*SEL_CallFuncO)(CCObject*); typedef void (CCObject::*SEL_MenuHandler)(CCObject*); //if button ,do CCEvent *evnet 參數 typedef void (CCObject::*SEL_EventHandler)(CCEvent*); typedef int (CCObject::*SEL_Compare)(CCObject*); //各類回調函數接口!!! #define schedule_selector(_SELECTOR) (SEL_SCHEDULE)(&_SELECTOR) #define callfunc_selector(_SELECTOR) (SEL_CallFunc)(&_SELECTOR) #define callfuncN_selector(_SELECTOR) (SEL_CallFuncN)(&_SELECTOR) #define callfuncND_selector(_SELECTOR) (SEL_CallFuncND)(&_SELECTOR) #define callfuncO_selector(_SELECTOR) (SEL_CallFuncO)(&_SELECTOR) #define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR) #define event_selector(_SELECTOR) (SEL_EventHandler)(&_SELECTOR) #define compare_selector(_SELECTOR) (SEL_Compare)(&_SELECTOR) // end of base_nodes group /// @} NS_CC_END #endif // __CCOBJECT_H__
/**************************************************************************** Copyright (c) 2010 cocos2d-x.org http://www.cocos2d-x.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "CCObject.h" #include "CCAutoreleasePool.h" #include "ccMacros.h" #include "script_support/CCScriptSupport.h" NS_CC_BEGIN CCObject* CCCopying::copyWithZone(CCZone *pZone) { CC_UNUSED_PARAM(pZone); CCAssert(0, "not implement"); return 0; } /************************************************************************/ /* 構造函數 */ /************************************************************************/ CCObject::CCObject(void) : m_nLuaID(0) , m_uReference(1) // when the object is created, the reference count of it is 1 , m_uAutoReleaseCount(0) { static unsigned int uObjectCount = 0; m_uID = ++uObjectCount; } CCObject::~CCObject(void) { // if the object is managed, we should remove it // from pool manager if (m_uAutoReleaseCount > 0) { CCPoolManager::sharedPoolManager()->removeObject(this); } // if the object is referenced by Lua engine, remove it if (m_nLuaID) { CCScriptEngineManager::sharedManager()->getScriptEngine()->removeScriptObjectByCCObject(this); } else { CCScriptEngineProtocol* pEngine = CCScriptEngineManager::sharedManager()->getScriptEngine(); if (pEngine != NULL && pEngine->getScriptType() == kScriptTypeJavascript) { pEngine->removeScriptObjectByCCObject(this); } } } CCObject* CCObject::copy() { return copyWithZone(0); } //當引用計數爲0時,釋放對象 delete void CCObject::release(void) { CCAssert(m_uReference > 0, "reference count should greater than 0"); --m_uReference; if (m_uReference == 0) { delete this; } } /************************************************************************/ /* 引用計數 +1 標記對象被引用 */ /************************************************************************/ void CCObject::retain(void) { CCAssert(m_uReference > 0, "reference count should greater than 0"); ++m_uReference; } //將對象添加到釋放池中 CCObject* CCObject::autorelease(void) { CCPoolManager::sharedPoolManager()->addObject(this); return this; } //判斷是否單引用 bool CCObject::isSingleReference(void) const { return m_uReference == 1; } unsigned int CCObject::retainCount(void) const { return m_uReference; } bool CCObject::isEqual(const CCObject *pObject) { return this == pObject; } void CCObject::acceptVisitor(CCDataVisitor &visitor) { visitor.visitObject(this); } NS_CC_END
/**************************************************************************** Copyright (c) 2010 cocos2d-x.org http://www.cocos2d-x.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #ifndef __AUTORELEASEPOOL_H__ #define __AUTORELEASEPOOL_H__ #include "CCObject.h" #include "CCArray.h" NS_CC_BEGIN /** * @addtogroup base_nodes * @{ */ class CC_DLL CCAutoreleasePool : public CCObject { CCArray* m_pManagedObjectArray; public: CCAutoreleasePool(void); ~CCAutoreleasePool(void); void addObject(CCObject *pObject); void removeObject(CCObject *pObject); void clear(); }; //自動釋放池 class CC_DLL CCPoolManager { CCArray* m_pReleasePoolStack; CCAutoreleasePool* m_pCurReleasePool; CCAutoreleasePool* getCurReleasePool(); public: CCPoolManager(); ~CCPoolManager(); void finalize(); void push(); void pop(); void removeObject(CCObject* pObject); void addObject(CCObject* pObject); static CCPoolManager* sharedPoolManager(); static void purgePoolManager(); friend class CCAutoreleasePool; }; // end of base_nodes group /// @} NS_CC_END #endif //__AUTORELEASEPOOL_H__ /**************************************************************************** Copyright (c) 2010 cocos2d-x.org http://www.cocos2d-x.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "CCAutoreleasePool.h" #include "ccMacros.h" NS_CC_BEGIN static CCPoolManager* s_pPoolManager = NULL; //new 一個 array容器。緩存object對象 CCAutoreleasePool::CCAutoreleasePool(void) { m_pManagedObjectArray = new CCArray(); m_pManagedObjectArray->init(); } CCAutoreleasePool::~CCAutoreleasePool(void) { CC_SAFE_DELETE(m_pManagedObjectArray); } /************************************************************************/ /* */ /************************************************************************/ void CCAutoreleasePool::addObject(CCObject* pObject) { m_pManagedObjectArray->addObject(pObject); CCAssert(pObject->m_uReference > 1, "reference count should be greater than 1"); ++(pObject->m_uAutoReleaseCount); //釋放對象 ,若是new 一個 ,那麼要標記對象+1 ,回調函數retain(),不然會建立對象失敗 pObject->release(); // no ref count, in this case autorelease pool added. } //就是一個從數組中移除對象,java知道吧 List同樣的 void CCAutoreleasePool::removeObject(CCObject* pObject) { for (unsigned int i = 0; i < pObject->m_uAutoReleaseCount; ++i) { m_pManagedObjectArray->removeObject(pObject, false); } } //釋放池中全部對象,在每一幀後,message loop,將會刪除autoRelease的對象 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); //(*it)->release(); //delete (*it); #ifdef _DEBUG nIndex--; #endif } m_pManagedObjectArray->removeAllObjects(); } } //-------------------------------------------------------------------- // // CCPoolManager // //-------------------------------------------------------------------- CCPoolManager* CCPoolManager::sharedPoolManager() { if (s_pPoolManager == NULL) { s_pPoolManager = new CCPoolManager(); } return s_pPoolManager; } void CCPoolManager::purgePoolManager() { CC_SAFE_DELETE(s_pPoolManager); } CCPoolManager::CCPoolManager() { m_pReleasePoolStack = new CCArray(); m_pReleasePoolStack->init(); m_pCurReleasePool = 0; } 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) { //CCAutoreleasePool* pReleasePool; CCObject* pObj = NULL; CCARRAY_FOREACH(m_pReleasePoolStack, pObj) { if(!pObj) break; CCAutoreleasePool* pPool = (CCAutoreleasePool*)pObj; pPool->clear(); } } } void CCPoolManager::push() { CCAutoreleasePool* pPool = new CCAutoreleasePool(); //ref = 1 m_pCurReleasePool = pPool; m_pReleasePoolStack->addObject(pPool); //ref = 2 pPool->release(); //ref = 1 } 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 CCPoolManager::removeObject(CCObject* pObject) { CCAssert(m_pCurReleasePool, "current auto release pool should not be null"); m_pCurReleasePool->removeObject(pObject); } 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; } NS_CC_END
下面一段摘自:http://blog.csdn.net/ring0hx/article/details/7946397 oop
其實這裏的自動並無咱們想得那麼好,對於像C#,Java這種託管語言,虛擬機爲你完成了全部內存管理工做,程序員徹底從內存分配和釋放中解脫了出來。cocos2dx的autorelease只不過每幀結束後自動在爲咱們釋放了一次對象, 若是咱們但願建立的對象在下一幀仍然可使用,咱們須要顯式地retain一下這個對象或者把對象加入到集合中(集合會幫咱們retain一次)。既然retain了,咱們仍是不能忘記在適當的地方release。比較常見的用法是建立一個autorelease對象做爲類成員變量,咱們在經過靜態方法獲得實例的指針後除了賦值給類成員,還要retain一次,而後在類的析構函數中release一次。若是沒有retain,之後使用該成員的時候就會由於對象被銷燬而發生內存訪問錯誤,這是新手很容易遇到的陷阱。 學習
想了解更多 你也能夠看這裏,我的以爲這裏翻譯,以及寫的都不錯:http://my.oschina.net/wangxuanyihaha/blog/131735
綜上所述,2dc引擎中建立了對象 記得添加到對象池中,以便在合適的時機2dx引擎幫你回收內存,其實這個也不是大問題 潔身自好就沒事的( 上了廁所要搽乾淨pp) 你以爲呢?ps:本系列文章會持續更新,後期就會直接根據各個模塊單獨demo上起,最後出個遊戲demo,有問題的請留言,互相學習