cocos2dx가 보기에 아름다운 인용계수로 인한 메모리 유출 (1) CCCallFunc 대상
인용 수는 다언할 필요가 없다. 다음은 RC라고 약칭한다.
RC의 두 가지 기본 원칙을 먼저 말씀드리겠습니다.
1. new와 delete 대상을 직접 사용하지 않고 RC를 통해 실현되며 RC는 0이고 대상은 소각됩니다.cocos2dx에서retain,release,autoRelease를 통해 실현됩니다.
2. 대상을 사용하려면 먼저retain,release를 다 써야 한다. 왜냐하면 이렇게 하지 않으면 사용하고 있는 물건이 누구에게 방출되었는지 알 수 없기 때문이다.특히 autoRelease가 있습니다.
만약 모두가 이 두 가지 원칙을 엄격히 준수한다면 메모리는 유출되지 않을 것이다.
나는 이전에도 이렇게 생각했지만, 나중에 나는 이것이 단지 보기에 매우 아름다울 뿐이라는 것을 발견하였다.
android의'독해'를 많이 입은 저는 최근에 프로젝트에서 이런 문제에 부딪혔습니다. 메모리의 점용은 줄어들지 않고 몇 장면을 더 전환하면 메모리 문제로 인해 시스템에 의해 죽습니다.단점 분노는 현재 장면에서 분석구를 사용하지 않은 것을 발견했다.소각해야 할 장면이 소각되지 않아 메모리 유출이 일어났다는 것이다.
왜냐하면 내가 button 컨트롤을 사용자 정의했기 때문이다. 다음과 같다.
class LCButton : public CCControl
{
public:
void init(const char* normalPath , const char* highlightPath , const char* disablePath , CCCallFunc *active , CCCallFunc *disactice);
static LCButton* create(const char* normalPath , const char* highlightPath , const char* disablePath , CCCallFunc *active , CCCallFunc *disactice , int priority = -127);
void setDownSelector(CCCallFunc *call);
void setUpSelector(CCCallFunc *call);
private:
CCCallFunc *beginSelector;
CCCallFunc *endSelector;
};
그 중에서 클릭 이벤트의 리셋에 대해 저는 CCCallfunc와 그 파의 아들 클래스로 실현했습니다. 왜냐하면 저는 CCCallfunc라는 클래스가 존재하는 의미가 바로 리셋을 하는 것이라고 생각하기 때문입니다.그렇다면 위에서 언급한 RC 원칙에 따라 나는 이렇게 써야 한다.
void LCButton::setDownSelector(CCCallFunc *call)
{
if(beginSelector)
{
beginSelector->release();
}
beginSelector = call ;
CC_SAFE_RETAIN(beginSelector);
}
이 대상의 존재 생명 주기 내에 이 리셋은 모두 작용해야 한다. 메모리를 방출하는 작업은 분석에 놓아야 한다. 그러면 나는 분석에서beginSelector를 방출해야 한다.
LCButton::~LCButton(void)
{
CC_SAFE_RELEASE(beginSelector);
}
그리고 외부에서 이 구성 요소의 클래스를 사용합니다. 저도 이렇게 처리했습니다.create가 나온 후에retain, 분석 구조release가 메모리를 방출합니다.
문제는 다음과 같습니다. CCCallfunc의 create 함수를 살펴보십시오.
CCCallFunc * CCCallFunc::create(CCObject* pSelectorTarget, SEL_CallFunc selector)
{
CCCallFunc *pRet = new CCCallFunc();
if (pRet && pRet->initWithTarget(pSelectorTarget)) { }
}
bool CCCallFunc::initWithTarget(CCObject* pSelectorTarget) {
if (pSelectorTarget)
{
pSelectorTarget->retain();
}
if (m_pSelectorTarget)
{
m_pSelectorTarget->release();
}
}
전송된this 바늘에 대해retain을 한 번 했습니다.
그러면 이callfunc 대상은 외부 장면this에 대한 인용을 저장하고,callfunc 대상이 방출되면this의 인용을 방출합니다.그러나callfunc는 나의button 컨트롤러에 의해 보유되고,button은callfunc를 방출하지만,button은this에 의해 보유되고,this는button을 방출한다.
정리해 보면this->button->callfunc->this와 같은 순환 인용 관계입니다.사라진 자물쇠 하나에 해당해서 모두가 풀 수 없다.
이 문제를 해결하려면 가장 간단한 것은child를 가진release를 앞당기는 것이다. 예를 들어onExit에 미리 가서 하는 것이다.그러나 이것은 디자인 이념과 어긋난다. 메모리를 방출하는 것은 분석해서 해야 할 일이기 때문이다.onExit는 청소만 합니다.cocos2dx 원본의 분석과 onExit 함수를 보십시오:
CCNode::~CCNode(void)
{
CC_SAFE_RELEASE(m_pActionManager);
CC_SAFE_RELEASE(m_pScheduler);
CC_SAFE_RELEASE(m_pCamera);
CC_SAFE_RELEASE(m_pGrid);
CC_SAFE_RELEASE(m_pShaderProgram);
CC_SAFE_RELEASE(m_pUserObject);
CC_SAFE_RELEASE(m_pChildren);
m_pComponentContainer->removeAll();
CC_SAFE_DELETE(m_pComponentContainer);
}
void CCNode::onExit()
{
this->pauseSchedulerAndActions();
m_bRunning = false;
arrayMakeObjectsPerformSelector(m_pChildren, onExit, CCNode*);
}
또한 onExit에서 청소를 하고 메모리 방출을 분석한다.
그럼 또 하나는 CCCallfunc에서 리턴을 하지 않고 CCMenu에 있는create를 보는 것이다.
CCMenuItem* CCMenuItem::create(CCObject *rec, SEL_MenuHandler selector)
{
CCMenuItem *pRet = new CCMenuItem();
pRet->initWithTarget(rec, selector);
pRet->autorelease();
return pRet;
}
bool CCMenuItem::initWithTarget(CCObject *rec, SEL_MenuHandler selector)
{
setAnchorPoint(ccp(0.5f, 0.5f));
m_pListener = rec;
m_pfnSelector = selector;
m_bEnabled = true;
m_bSelected = false;
return true;
}
안에 this에 대한 리턴 처리가 없습니다.그러나 봉인된 리셋류가 있어서 사용하지 않고 단독으로 바퀴를 만드는 행위를 반복하는 것 같다.
CCCallfunc를 보면this의retain이 어떤 경우에도 필요합니다.예를 들어 전체적인 schedule 스케줄링을 할 때this가 풀려나면 아무것도 없다.
마지막으로 가장 실현하기 쉬운 첫 번째 방법을 선택하여 onExit로 앞당겼다.
더 좋은 방법이 있습니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.