There are two ways to fix issue: refactoring which sanitizes code and direct tracing.
The first way is to make all nodes to use clean CCNode lifecycle:
# C++ constructor sets all raw pointers and numbers to 0 (but it’s better to have smart pointers which automatically init nested pointer with 0)
# init[...]([...]) creates children nodes and attaches them to this node
# onEnter() turns on actions, scheduled methods, scheduled update, touch/keypad/IME event subscriptions
# onExit() stops all actions, scheduled methods, scheduled update, touch/keypad/IME event subscriptions
# cleanup() finally removes node from own arrays/dictionaries for remove all links to it, so after calling cleanup() parent will remove object from own dictionary m_children which should be the last link to node, node will be deleted.
Second way includes a little or a big tweak in CCNode sources: create global static variable in CCNode.cpp which will keep an std::vector or std::set of living nodes, modify this array from CCNode constructor and destructor. You’ll also need IDE which can display content of std::vector or std::set in debugger (QtCreator, probably Visual Studio and XCode can do it).
We’ve used more complex approach: added method which collects functions stack trace at given point and stored stacktrace each time when retain/release was called for CCNode, so we’ve seen who keeps link to node.
We’ve used more complex approach: added method which collects functions stack trace at given point and stored stacktrace each time when retain/release was called for CCNode, so we’ve seen who keeps link to node.
hi, how did you collect function stack trace? I’m very interested at this~
There are two ways to fix issue: refactoring which sanitizes code and direct tracing.
>
The first way is to make all nodes to use clean CCNode lifecycle:
# C++ constructor sets all raw pointers and numbers to 0 (but it’s better to have smart pointers which automatically init nested pointer with 0)
# init[...]([...]) creates children nodes and attaches them to this node
# onEnter() turns on actions, scheduled methods, scheduled update, touch/keypad/IME event subscriptions
# onExit() stops all actions, scheduled methods, scheduled update, touch/keypad/IME event subscriptions
# cleanup() finally removes node from own arrays/dictionaries for remove all links to it, so after calling cleanup() parent will remove object from own dictionary m_children which should be the last link to node, node will be deleted.
>
Second way includes a little or a big tweak in CCNode sources: create global static variable in CCNode.cpp which will keep an std::vector or std::set of living nodes, modify this array from CCNode constructor and destructor. You’ll also need IDE which can display content of std::vector or std::set in debugger (QtCreator, probably Visual Studio and XCode can do it).
>
We’ve used more complex approach: added method which collects functions stack trace at given point and stored stacktrace each time when retain/release was called for CCNode, so we’ve seen who keeps link to node.
Thanks for your replay!
I doing all this things but still have a problem with memory
Can I provide you an example of what I do and maybe you will have some time to explain me where is my mistake? Please.
So.
CCSomeClass.h:
class CCSomeClass : public CCSprite
{
protected:
int m_SomeField;
CCSprite* m_SomeSpriteField;
CCSomeClass(/** Maybe some params */);
public:
static CCSomeClass* create(/** Maybe some params */);
~CCSomeClass();
void onEnter();
void onExit();
}
CCSomeClass.cpp:
CCSomeClass::~CCSomeClass()
{
this->removeAllChildrenAndCleanup(true); // Or this->cleanup(); Does't matter.
}
CCSomeClass::CCSomeClass(/** Maybe some params */) :
CCSprite(/** Maybe some params */),
m_SomeField(0),
m_SomeSpriteField(0)
{
// Do some stuffs.
}
CCSomeClass* CCSomeClass::create(/** Maybe some params */)
{
CCSomeClass* cl = new CCSomeClass(/** Maybe some params */);
cl->autorelease();
cl->retain(); // Use retain here for access this object if I need it and really don't forget to call release() after this object don't need me more.
return cl;
}
void CCSomeClass::onEnter()
{
CCSprite::onEnter();
this->scheduleUpdate(); // Need it for use update(float deltaTime); method;
}
void CCSomeClass::onExit()
{
CCSprite::onExit();
this->unscheduleUpdate();
}
So after this object no need me no more and I release it by calling release(); or CC_SAFE_RELEASE(); the texture it “hold” is unloading but memory are not
i debug my exe at windows also show the problem,and i put a break point at the CCAutoreleasePool.When enter the init method of my helloworld,there create two CCAutoreleasePool instance,and they are put at the CCPoolManager.When the below code happens void CCDisplayLinkDirector::mainLoop(void) { if (m_bPurgeDirecotorInNextLoop) { m_bPurgeDirecotorInNextLoop = false; purgeDirector(); } else if (! m_bInvalid) { drawScene(); // release the objects CCPoolManager::sharedPoolManager()->pop(); } }
there is only one CCAutoreleasePool there without create new CCAutoreleasePool instance.so when you replace your scene,every spites you create are put to the first CCAutoreleasePool instance,which is
being release at the end.
the solution maybe you can add CCPoolManager::sharedPoolManager()->push(); in front of drawScene();
You need to release all sprite frames that use the texture you want to remove. If you take a look at CCSpriteFrame codes you may find the following:
if (pobTexture)
{
pobTexture~~>retain;
}
And I would strongly recommend to Ctrl+Z back from manually calling new and delete, most likely that will lead you to severe pains in~~the ass- future.
Snippet [1] implements function std::string ccGetStackTrace(const std::string &title) that returns string with 10 stack traces. Works on Linux, MacOSX, iOS, android.
You can define CCObject::retain() and CCObject::release() as virtual, override them in CCNode, create CCNode member of type std::vector<std::string> to keep stacktraces from all retain/release requests and so debug who keeps link on your node. Don’t forget to also keep global set of living nodes — otherwise you’ll not able to access stacktraces from debugger.
From my experience, such tracing makes app 4 times slower.
Snippet [1] implements function std::string ccGetStackTrace(const std::string &title) that returns string with 10 stack traces. Works on Linux, MacOSX, iOS, android.
>
Didn’t know the existence of such API before, will try this out, in debug mode, so hopefully no need to worry about performance.