[기초]Cocos2d-x 메모리 관리 메커니즘
본 논문 의 저작권 은 젤리 가 소유 하고 싶 습 니 다.전 재 를 환영 합 니 다.그러나 작가 의 동의 없 이 이 성명 을 보류 하고 글 페이지 의 뚜렷 한 위치 에서 원문 링크 를 제시 해 야 합 니 다.그렇지 않 으 면 법률 적 책임 을 추궁 할 권 리 를 보류 합 니 다.만약 이 문장 이 너 에 게 도움 이 된다 면,너 는 할 수 있다.
커피 한잔 주세요.
»
본문 링크:http://www.jellythink.com/archives/776
»
본 사이트 구독:http://www.jellythink.com/feed
»
젤리 » 원본 링크:http://www.jellythink.com/archives/776
[본문]
영원히 변 하지 않 는 물건
지금까지 메모리 가 매우 싸 지만 무한대 로 사용 할 수 있 는 것 도 아 닙 니 다.특히 모 바 일 에서 그 정도 의 메모리,그 많은 앱 을 앞 다 투어 사용 해 야 합 니 다.잘 모 르 겠 습 니 다.당신 이 차지 하 는 메모리 가 너무 많 습 니 다.시스템 은 당신 의 앱 을 직접 처리 합 니 다.그래서 우 리 는 또 자주 이야기 해 야 합 니 다.메모리 관리.COM 개발 을 정리 할 때 COM 의 메모리 관리 모델 을 분석 한 적 이 있다.루 아 를 정리 할 때 루 아의 메모리 회수 메커니즘 도 분석 했다.며칠 전 에는 C++의 스마트 포인터 가 메모리 사용 에 대한 응용 도 전문 적 으로 썼 다.이 를 통 해 알 수 있 듯 이 메모리 관 리 는 언어 차원 이 든 라 이브 러 리 차원 이 든 모두 엄격 한 기준 과 실 시 를 가진다.Cocos2d-x 에 있어 서도 마찬가지다.그렇다면 Cocos2d-x 에 서 는 메모리 관 리 를 어떻게 합 니까?이 글 은 Cocos2d-x 의 메모리 관리 에 관 한 지식 을 정리 하 겠 습 니 다.면접 관 의 다섯 손가락 관문 을 가볍게 넘 길 수 있 게 해 드 립 니 다.
Cocos2d-x 메모리 관리
메모리 관리 라 는 추상 적 인 것 을 탐구 하 는 데 가장 간단 한 방법 은 코드 를 통 해 연구 하 는 것 이다.먼저 간단 한 장면 을 만들어 서 Cocos2d-x 가 대상 을 만 들 때 무엇 을 했 는 지 살 펴 보 자.
Scene 만 들 기:
auto scene = Scene::create();
함수.
create
정적 함수 입 니 다.보 세 요.
create
함수 의 원본 코드:
Scene *Scene::create()
{
Scene *ret = new Scene();
if (ret && ret->init())
{
ret->autorelease();
return ret;
}
else
{
CC_SAFE_DELETE(ret);
return nullptr;
}
}
이 제 는 Cocos2d-x 의 메모리 관리 에 관 한 지식 이 언급 되 었 다.Cocos2d-x 에서 대상 의 생 성과 초기 화 는 모두 사용 하 는 new 와
init
함수 의 조합 방식 입 니 다.이런 방식 을 2 단 식 생 성 이 라 고 합 니 다.C++에서 구조 함수 가 반환 값 이 없 기 때문에 구조 함 수 를 통 해 초기 화의 성공 과 실 패 를 확정 할 수 없습니다.그래서 Cocos2d-x 에서 이런 2 단 식 생 성 방식 을 크게 사 용 했 습 니 다.사용 하기에 괜 찮 습 니 다.앞으로 자신의 프로젝트 에서 도 채용 할 수 있다.이런 방식 은 Cocos2d-x 에서 자주 사용 되 기 때문에 그 녀석 들 을 터치 하여 매크로 를 만 들 었 다.
CREATE_FUNC
우리 클래스 도 이러한 2 단 식 으로 만 드 는 방식 을 사용 하려 면 우리 클래스 에 다음 과 같은 코드 를 추가 해 야 합 니 다.CREATE_FUNC(classname);
동시에 init 함 수 를 정의 해 야 합 니 다.그러면 OK 입 니 다.우리 이 매크로 를 보 자.
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
__TYPE__ *pRet = new __TYPE__(); \
if (pRet && pRet->init()) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \
} \
}
그런데 이 물건 들 도 모두 기본 적 인 C++지식 입 니 다.할 말 이 별로 없습니다.코드 에 있 는
ret->autorelease()
을 보면 망연자실 합 니 다.네,Cocos2d-x 의 메모리 관리 촉각 을 보 았 습 니 다.ret->autorelease()
뭐 예요?내 가 create 함 수 를 사용 하여 장면 을 만 든 후에 나 는 delete 에 가지 않 았 다.이것 도 문제 가 없다.문 제 는 바로 이autorelease
의 사용 에서 발생 했다.서막 이 끝 났 으 니 진정 으로 Cocos2d-x 의 메모리 관 리 를 시작 합 시다.Cocos2d-x 에서 메모리 관리 에 관 한 종 류 는 다음 과 같 습 니 다.
Ref 클래스;
AutoreleasePool 클래스;
PoolManager 클래스.
Ref 류 는 거의 Cocos2d-x 의 모든 종류의 부류 로 Cocos2d-x 에서 메모리 관리의 가장 중요 한 일환 이다.위 에서 말 한
autorelease
함 수 는 Ref 류 의 구성원 함수 에 대해 Cocos2d-x 에서 Ref 류 를 계승 하 는 모든 클래스 는 Cocos2d-x 의 메모리 관 리 를 사용 할 수 있다.AutoreleasePool 클래스 는 자동 방출 대상 을 관리 하 는 데 사 용 됩 니 다.
PoolManager 는 모든 AutoreleasePool 을 관리 하 는 데 사 용 됩 니 다.이 종 류 는 단일 모드 로 이 루어 집 니 다.
다음은 상기 세 가지 유형의 소스 코드 를 분석 함으로써 Cocos2d-x 가 어떻게 메모리 관 리 를 하 는 지 살 펴 보 겠 습 니 다.
Ref 류
먼저 Ref 류 의 정 의 를 살 펴 보 겠 습 니 다.다음은 Ref 류 의 헤더 파일 정의 입 니 다.
class CC_DLL Ref
{
public:
/**
*
*
*/
void retain();
/**
*
* , 0 ,
*/
void release();
/**
*
*
* , ,
* release , 0 , 。
*/
Ref* autorelease();
/**
*
* , 1
*/
unsigned int getReferenceCount() const;
};
...에 대하 여
release
함수 의 실현 은 여기 서 특별히 정리 해 야 합 니 다.먼저 그것 의 실현 을 보 세 요.
void Ref::release()
{
CCASSERT(_referenceCount > 0, "reference count should greater than 0");
--_referenceCount;
if (_referenceCount == 0)
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
auto poolManager = PoolManager::getInstance();
if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
{
// , Cocos2d-x
// 0, autorelease ,
// , 0 , , autorelease ,
// autorelease , , Cocos2d-x
// 。
//
// new/retain autorelease/release
CCASSERT(false, "The reference shouldn't be 0 because it is still in autorelease pool.");
}
#endif
delete this;
}
}
위 에서 도 말 했 듯 이 new 와 autorelease 는 일치 하 게 사용 해 야 합 니 다.retain 과 release 도 일치 하 게 사용 해 야 합 니 다.그렇지 않 으 면 단언 오류 나 메모리 유출 이 발생 할 수 있 습 니 다.비 Debug 모드 에서 바로 물 러 날 수 있 습 니 다.이것 이 바로 우리 가 create 함 수 를 사용 할 때 new 가 성공 한 후에 autorelease 를 호출 하여 이 대상 을 자동 방출 탱크 에 넣 는 이유 입 니 다.그리고 우리 가 다시 이 대상 을 얻 고 이 대상 을 사용 하려 면 retain 을 사용 하여 이 대상 의 소유권 을 다시 얻어 야 합 니 다.물론 사용 이 끝 난 후에 release 를 호출 하여 수 동 으로 석방 작업 을 완성 하 는 것 을 기억 해 야 합 니 다.이것 은 당신 의 임무 입 니 다.예 를 들 어 다음 코드:
auto obj = Scene::create();
obj->autorelease(); // Error
이것 은 잘못된 것 입 니 다.create 에서 생 성 에 성공 한 상태 에서 obj 대상 을 autorelease pool 에 넣 었 습 니 다.autorelease pool 을 다시 넣 으 면 autorelease pool 을 없 애 면 한 대상 을 두 번 이나 없 애 는 경우 가 발생 하고 프로그램의 crash 가 발생 합 니 다.예 를 들 어 다음 코드 도 잘못 되 었 습 니 다.
auto obj = Scene::create();
obj->release(); // Error
create 함 수 를 사용 하여 대상 을 만 든 후,obj 는 소유권 이 없 으 며,release 를 다시 호출 하면 잘못된 대상 이 방출 됩 니 다.정확 한 방법 은 다음 과 같다.
auto obj = Scene::create(); // retain release ,release autorelease ( create ) retain
obj->retain();
obj->release();
이 인용 수 는 COM 의 AddRef 와 Release 를 떠 올 리 게 한다.
AutoreleasePool 클래스
Autorelease Pool 류 는 Ref 류 의 유원 류 입 니 다.먼저 Autorelease 류 의 성명 을 보십시오.
class CC_DLL AutoreleasePool
{
public:
/**
* AutoreleasePool ,
* , ,AutoreleasePool , RAII
*/
AutoreleasePool();
/**
* autorelease pool
* , 。
*/
AutoreleasePool(const std::string &name);
~AutoreleasePool();
/**
* autorelease pool ref
* ( )
* , release()
*/
void addObject(Ref *object);
/**
*
* release()
*/
void clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
/**
*
*/
bool isClearing() const { return _isClearing; };
#endif
/**
* Ref
*/
bool contains(Ref* object) const;
/**
* autorelease pool
*/
void dump();
private:
/**
* std::vector
*/
std::vector<Ref*> _managedObjectArray;
std::string _name;
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
/**
* The flag for checking whether the pool is doing `clear` operation.
*/
bool _isClearing;
#endif
};
AutoreleasePool 류 에 있어 서 그 실현 은 매우 간단 합 니 다.대상 을 std::vector 에 간단하게 저장 하 는 것 입 니 다.이 AutoreleasePool 을 풀 때 std::vector 에 저 장 된 대상 에 게 해당 하 는 release 함 수 를 순서대로 호출 하여 대상 의 자동 방출 을 완성 하 는 것 입 니 다.
PoolManager 클래스
이 물건 은 또 무엇 을 하 는 것 입 니까?우리 가 AutoreleasePool 의 소스 코드 를 읽 을 때 구조 함수 에서 다음 과 같은 코드 를 발견 할 수 있 습 니 다.
AutoreleasePool::AutoreleasePool()
: _name("")
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
, _isClearing(false)
#endif
{
_managedObjectArray.reserve(150);
PoolManager::getInstance()->push(this);
}
AutoreleasePool 의 분석 함수 에는 다음 과 같은 코드 가 있 습 니 다.
AutoreleasePool::~AutoreleasePool()
{
CCLOGINFO("deallocing AutoreleasePool: %p", this);
clear();
PoolManager::getInstance()->pop();
}
아,원래 우 리 는 AutoreleasePool 대상 을 PoolManager 에 다시 넣 었 군요.원래 PoolManager 클래스 는 모든 AutoreleasePool 클래스 를 관리 하 는 데 사용 되 고 하나의 예 모드 로 이 루어 집 니 다.이 PoolManger 는 AutoreleasePool 대상 지침 을 저장 하 는 stack 이 있 습 니 다.이 stack 은 std:vector 에 의 해 이 루어 집 니 다.주의해 야 할 것 은 cocos2d-x 의 단일 사례 류 는 모두 스 레 드 가 안전 하지 않 고 메모리 관리 와 밀접 한 관 계 를 가 진 PoolManager 류 도 예외 가 아니 므 로 다 중 스 레 드 에서 cocos2d-x 의 인 터 페 이 스 를 사용 할 때 메모리 관리 문 제 를 특히 주의해 야 한다.더욱 안전 한 단일 모델 에 대해 관심 이 있 는 학생 들 은 이 를 읽 을 수 있다.
》。다음은 PoolManager 의 헤더 파일 정 의 를 살 펴 보 겠 습 니 다.
class CC_DLL PoolManager
{
public:
/**
*
*/
static PoolManager* getInstance();
/**
*
*/
static void destroyInstance();
/**
* autorelease pool, , autorelease pool
* , release pool, autorelease pool PoolManager
*/
AutoreleasePool *getCurrentPool() const;
/**
* autorelease pool
*/
bool isObjectInPools(Ref* obj) const;
friend class AutoreleasePool;
private:
PoolManager();
~PoolManager();
/**
* AutoreleasePool PoolManager
*/
void push(AutoreleasePool *pool);
/**
* PoolManager AutoreleasePool
*/
void pop();
static PoolManager* s_singleInstance;
/**
* AutoreleasePool
*/
std::deque<AutoreleasePool*> _releasePoolStack;
AutoreleasePool *_curReleasePool;
};
PoolManager 의 각 함수 의 실현 에 대해 서도 매우 간단 합 니 다.여 기 는 피로 한 설명 을 하지 않 습 니 다.여러분 은 Cocos2d-x 의 소스 코드 를 읽 을 수 있 습 니 다.
문제 가 생 겼 다
이렇게 많은 말 을 했 고 코드 도 이렇게 많이 열 거 했 습 니 다.우 리 는 하나의 대상 을 만 든 후에 AutoreleasePool 에 넣 었 습 니 다.마지막 으로 AutoreleasePool 의 clear 함 수 를 호출 할 때 AutoreleasePool 이 관리 하 는 모든 대상 에 게 차례대로 release 작업 을 호출 합 니 다.아하!뭔 가 잘못된 것 같 습 니 다.저 는 최종 적 으로 누가 이 clear 함 수 를 호출 할 것 이 라 고 말 하지 않 았 습 니 다.예.감독 류 에 있 는 이 코드 를 보면 알 것 같 습 니 다.
void DisplayLinkDirector::mainLoop()
{
if (_purgeDirectorInNextLoop)
{
_purgeDirectorInNextLoop = false;
purgeDirector();
}
else if (! _invalid)
{
drawScene();
// release the objects
PoolManager::getInstance()->getCurrentPool()->clear();
}
}
위의 코드 가 설명 한 사실은 이미지 렌 더 링 의 주 순환 에서 현재 그래 픽 대상 이 현재 프레임 에 있다 면 디 스 플레이 함 수 를 호출 하고 Autorelease Pool:clear()를 호출 하여 이 대상 들 의 인용 수 를 줄 이 는 것 입 니 다.mainLoop 은 모든 프레임 이 자동 으로 호출 되 기 때문에 다음 프레임 에 서 는 이 대상 들 이 현재 AutoreleasePool 대상 에 의 해 한 번 씩 릴 리 스 되 었 습 니 다.이것 도 Autorelease Pool'자동'의 이유 이다.
총결산
자,총 결 된 차이 가 많 지 않 습 니 다.Cocos2d-x 의 메모리 관리 에 대한 총 결 된 차이 가 많 지 않 습 니 다.Cocos2d-x 의 메모리 관리 에 대해 저 는 개인 적 으로 이 대상 의 인용 계수,retain 과 release,new 와 autorelease 가 일치 하 게 사용 되 어야 하 며 불필요 한 오류 가 발생 하지 않도록 해 야 한다 고 생각 합 니 다.이렇게 많아
종이 위 에서 얻 은 것 은 결국 얕 게 느껴 져 서,이 일 을 몸소 해 야 한 다 는 것 을 절대 알 지 못 한다.
실제 사용 을 거 쳐 코드 의 세련 을 거 쳐 야만 이런 것들 을 더욱 잘 파악 할 수 있다.Cocos2d-x 에서 많은 부분 에서 autorelease 나 retain 이 진행 되 었 습 니 다.우 리 는 다시 이런 조작 을 할 필요 가 없습니다.예 를 들 어 create,예 를 들 어 addChild 방법 으로 하위 노드 를 추가 할 때 자동 으로 retain 을 호출 합 니 다.대응 하 는 removeChild 를 통 해 하위 노드 를 제거 할 때 자동 으로 release 를 호출 합 니 다.이런 곳 들 은 조금 만 주의 하지 않 으 면 너 를 구덩이 에 빠 뜨 릴 수 있다.열심히 해,얘 들 아.
【부록】
원본 주소:http://www.jellythink.com/archives/776
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
MRC 아래의 initWithFormat:과stringWithFormat:이 두 가지 방법은 같다.우리가 알아야 할 것은 어떻게 그들을 정확하게 사용하는가이다.initWithFormat는 새로운 alloc 실례에 호출되어야 하는 실례적인 방법입니다. 이것은 당신이 그것을 석방할 책임이 있...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.