Memory Management: Memory dealocations not happening.

Hi guys, I’m having some memory management issues and I’m getting really confused by it, so I’d like to defer to you’re collective greater knowledge.

I have a game that switches between scenes, each scene is pretty standard (sprites, buttons etc). I suspected that Objects might not be getting deallocated properly and after profiling it appears I was right.

My code is much chunkier than what follows, but this should give you the idea of how I’m trying to go about doing things.

CCScene* MainMenuScreen::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::create();
    MainMenuScreen *layer = MainMenuScreen::create();
    scene->addChild(layer);
    return scene;
}

//********************************************************************
// Initilisation Method.
// Not called directly. 
//********************************************************************
bool MainMenuScreen::init()
{
    //////////////////////////////
    if ( !CCLayer::init() )
    {
        return false;
    }
    /////////////////////////////
    winSize = CCDirector::sharedDirector()->getWinSize();    
    _batchNode = CCSpriteBatchNode::create("FrontEndSprites.png");
    this->addChild(_batchNode);
    CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("FrontEndSprites.plist");
    // add "MainMenuScreen" splash screen"
    m_spriteBackground = CCSprite::createWithSpriteFrameName("Background.png");
    m_spriteBackground->setPosition( ccp(winSize.width/2, winSize.height/2) );
    // add the sprite as a child to this layer
    _batchNode->addChild(m_spriteBackground, 0);
    //Button to move the screen forward
    CCSprite* pPlayGameSprite = CCSprite::createWithSpriteFrameName("FE_Button_1_Pressed.png");
    CCSprite* pPlayGameSpritePressed = CCSprite::createWithSpriteFrameName("FE_Button_1.png");
    CCMenuItemSprite *pPlayGameButton = CCMenuItemSprite::create(
                                                              pPlayGameSprite,
                                                              pPlayGameSpritePressed,
                                                              this,
                                                              menu_selector(MainMenuScreen::MoveToPlayGame) );
    pPlayGameButton->setPosition( ccp(65, 80) );
    // create menu, it's an autorelease object
    pPlayGameMenu = CCMenu::create(pPlayGameButton, NULL);
    pPlayGameMenu->setTouchEnabled(false);
    pPlayGameMenu->setPosition( CCPointZero );
    pPlayGameMenu->setOpacity(0);
    this->addChild(pPlayGameMenu, 1);
    this->setTouchEnabled(false);
    return true;
m_pSprite = CCSprite::createWithSpriteFrameName("FE_Electric_001.png");
    m_pSprite->setPosition( ccp(winSize.width/2, (winSize.height/2) + 123.0f) );
    _batchNode->addChild(m_pSprite, 2);
}

void MainMenuScreen::release(){
    m_pSpriteAnimation->release();
    m_pSpiteAnimateAction->release();
    _batchNode->removeAllChildrenWithCleanup(true);
    this->removeAllChildrenWithCleanup(true);
    printf("Releasing Main Menu\n");
}

void MainMenuScreen::onExit(){
    this->unscheduleAllSelectors();
    this->release();
}

void MainMenuScreen::SetUpAnimation(){
CCArray *FrameArray = CCArray::create();
    FrameArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("Frame_001.png"));
    FrameArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("Frame_002.png"));
    FrameArray->addObject(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName("Frame_003.png"));
    //Create an Animation Object
    m_pSpriteAnimation = CCAnimation::create(FrameArray, (1.0f/FrameArray->count()));
    m_pSpriteAnimation->setRestoreOriginalFrame(true);
    m_pSpriteAnimation->setLoops(5);
    m_pSpriteAnimation->retain();
    //create the animate action and set up parameters
    m_pSpriteAnimateAction = CCAnimate::create(m_pSpriteAnimation);
    m_pSpriteAnimateAction->setDuration(1.0f);
    m_pSpriteAnimateAction->retain();
}

I hope this is enough to give you guys an idea of what I’m trying to do in my code.

My understanding is, if you explicitly call retain() on any object you have to explicitly call release() when you have finished using the object. I am trying to do this in the release() method in my MainMenuScreen class.

My second scene is set up exactly the same way and when I move between them, the profiling tool clearly shows that the allocations go up after switching one, then remain at the same level after every other switch. Unless I’m mistaken, this means that nothing is being deallocated properly.

onExit(), Release() and the destructor are all being called.

Any help anyone can give me would be greatly appreciated.

Try wrapping your code in <pre> </pre> tags. Like so:

     // code
Anyway, for your question.
void MainMenuScreen::onExit(){
     this->unscheduleAllSelectors();
     this->release();
}

this -> release; only releases the MainMenuScreen instance, and not its members and objects. You’d have to release* each and every object you’veretain()-ed.
However, most classes have a
create()* method which you can use ( and copy ) when creating a new instance. When create* is used, objects are set toautorelease()*, meaning, those objects will be automatically cleaned by the garbage collector when the time comes ( i.e., when no one else is referencing the object ).

Thanks for the reply, and the tag tip.

I think I’m doing what you’re tell me to do.

When I call this~~>release; in here :~~

void MainMenuScreen::onExit(){
     this->unscheduleAllSelectors();
     *this->release();*
}

This method gets called :-

void MainMenuScreen::release(){
m_pSpriteAnimation->release();
m_pSpiteAnimateAction->release();
_batchNode->removeAllChildrenWithCleanup(true);
this->removeAllChildrenWithCleanup(true);
printf("Releasing Main Menu\n");
}

Where I release all my retained objects. Unfortunately when I don’t call retain and leave them as an autorelease object then I get crashes after it gets released too early. Is this what you mean?

From what I see, the logic is correct and should release those objects.

Did you declare MainMenuScreen::release* asvirtual* in the header file?

// MainMenuScreen.h
class MainMenuScreen : public cocos2d::CCLayer {
private:
    // stuff
public:
    virtual void release();
}

Try declaring it as virtual and on your release method, add *CCLayer::release()* at the end.

I made it a virtual method and added CCLayer::release() however now I’m getting a crash.

It occurs in the this CCNode::cleanup() method after the MainMenuScreen::release() has been called. I have no idea why this is happening. Any other suggestions?

I’m gonna bump this because I’m no closer to finding an answer.

Any suggestions about how I can fix this or what I might be doing wrong would be greatly appreciated.

Hello there!

I too ran into some memory issues when I began profiling my cocos2dx game on the iphone and using profiler. What I found was that I needed to declare destructors virtual. I had some destructors that I didn’t declare virtual. And I notice that you have an CCArray. I found that in my code I had one area where I accidentally was making pointers to pointers within a ccarray and never releasing the pointers its one of those silly bugs worth a try to see if you are doing something similar. Also I found a tool called visual leak detector (VLD) its an open source lib that you can stick into your project and it outputs all your leaks once you close your project. The output is like a stack trace and you can double click on the locations and skim through the code. It’s pretty useful for me because I am working in Visual Studio so it saved me the time of making a build and transferring over to the mac then compiling on xcode transferring to the iphone ……

Hope this helped

Thanks for the reply, I’ve made all my destructors virtual, and unfortunately it hasn’t fixed my problem.

When I called release manually I’m getting a crash here:-

void CCNode::cleanup()
{
    // actions
    this->stopAllActions();
    this->unscheduleAllSelectors();    

    // timers
    arrayMakeObjectsPerformSelector(m_pChildren, cleanup, CCNode*); //Crash happens here EXC_BAD_ACCESS
}

which is called from here :-

void CCTransitionScene::cleanup()
{
    CCScene::cleanup();

    if( m_bIsSendCleanupToScene )
        m_pOutScene->cleanup();
}

Any suggestions as to what could be causing this?

EDIT: I should have said it was when I call CCLayer::release() I get the crash, like so:-

void MainMenuScreen::release(){
CCLayer::release();
    m_pSpriteAnimation->release();
    m_pSpiteAnimateAction->release();
    _batchNode->removeAllChildrenWithCleanup(true);
    this->removeAllChildrenWithCleanup(true);
    printf("Releasing Main Menu\n");
}
void MainMenuScreen::release(){
    CCLayer::release();
    m_pSpriteAnimation->release();
    m_pSpiteAnimateAction->release();
    _batchNode->removeAllChildrenWithCleanup(true);
    this->removeAllChildrenWithCleanup(true);
    printf("Releasing Main Menu\n");
}

You’re calling CCLayer::release* then you’re accessingthis* three lines after.
Have you tried calling *CCLayer::release()* after doing the clean up?
Also, could you provide what errors get reported by your debugger when it crashes?

Ok after plugging all the holes caused by some rather crappy programming on my part, the game no longer crashes.
However, after profiling again and looking at the Real Memory usage statistic I’m still no further forward and memory is still not being properly released.

As far as I can tell its not a leak. Memory usage maxes out at around 27mb no matter how many time I open any of the scenes and just never goes down no matter what I do.

I’ve profiled looking for leaks and I haven’t found any yet either.

So in short, I’m back to square one.

I think I might have narrowed it down to textures not being removed properly.

Currently I’m doing this in every init method for my scenes:-

CCSpriteFrameCache::sharedSpriteFrameCache()->removeUnusedSpriteFrames();
    CCTextureCache::sharedTextureCache()->removeUnusedTextures();

From the output I can see that the SpriteFrames are being removed but not the textures.

Can anyone shed any light on this?