2019独角兽企业重金招聘Python工程师标准>>>
2dx引擎中的对象内存管理模型,很简单就是一个对象池+引用计数,本着学好2dx的好奇心,先这里开走吧,紧接上面两节,首先我们看一个编码场景代码:
hello word :
#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-iphonevirtual bool init(); // there's no 'id' in cpp, so we recommend returning the class instance pointerstatic cocos2d::CCScene* scene();// a selector callbackvoid menuCloseCallback(CCObject* pSender);// implement the "static node()" method manuallyCREATE_FUNC(HelloWorld);
};#endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h"USING_NS_CC;CCScene* HelloWorld::scene()
{// 'scene' is an autorelease objectCCScene *scene = CCScene::create();// 'layer' is an autorelease objectHelloWorld *layer = HelloWorld::create();// add layer as a child to scenescene->addChild(layer);// return the scenereturn scene;
}// on "init" you need to initialize your instance
bool HelloWorld::init()
{//// 1. super init firstif ( !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 objectCCMenuItemImage *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 objectCCMenu* 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 labelCCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);// position the label on the center of the screenpLabel->setPosition(ccp(origin.x + visibleSize.width/2,origin.y + visibleSize.height - pLabel->getContentSize().height));// add the label as a child to this layerthis->addChild(pLabel, 1);// add "HelloWorld" splash screen"CCSprite* pSprite = CCSprite::create("HelloWorld.png");// position the sprite on the center of the screenpSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));// add the sprite as a child to this layerthis->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(),内存对象池会自动处理的;
接下来直接看内存模型+引用计数,内存对象缓存是用的CCArray;具体看下面代码片段,该有的注解都有了:
先是2dx中:object,java中所有对象的根接点,这里你可以这样“理解”:
/****************************************************************************
Copyright (c) 2010 cocos2d-x.orghttp://www.cocos2d-x.orgPermission 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 // EMSCRIPTENNS_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:// 对象IDunsigned int m_uID;// Lua reference idint 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.orghttp://www.cocos2d-x.orgPermission 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_BEGINCCObject* 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 managerif (m_uAutoReleaseCount > 0){CCPoolManager::sharedPoolManager()->removeObject(this);}// if the object is referenced by Lua engine, remove itif (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.orghttp://www.cocos2d-x.orgPermission 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.orghttp://www.cocos2d-x.orgPermission 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_BEGINstatic 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 _DEBUGint nIndex = m_pManagedObjectArray->count() - 1;
#endifCCObject* pObj = NULL;CCARRAY_FOREACH_REVERSE(m_pManagedObjectArray, pObj){if(!pObj)break;--(pObj->m_uAutoReleaseCount);//(*it)->release();//delete (*it);
#ifdef _DEBUGnIndex--;
#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 = 1m_pCurReleasePool = pPool;m_pReleasePoolStack->addObject(pPool); //ref = 2pPool->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
其实这里的自动并没有我们想得那么好,对于像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,有问题的请留言,互相学习