released object won't dealloc - ideas?

Member
Posts: 73
Joined: 2009.03
Post: #1
To simplify my situation, it's like this.

Code:
@interface Globals
{
  Player *player;
}

Globals setup
{
  player = [Player init retain]; //etc...
}

Globals cleanup
{
  if (player)
  {
    [player release];
    player = nil;
  }
}

When my main code calls [Globals cleanup], I can verify that player gets released. However, the delloc method for the Player class is not getting called. There is no other place in my entire program that creates or retains the player object. It is only done in the Globals setup function, and I have verified by using NSLog messages that it is not being called more than once before the next cleanup.

Any thoughts and help are appreciated.
Quote this message in a reply
Member
Posts: 144
Joined: 2009.11
Post: #2
Gillissie Wrote:To simplify my situation, it's like this.

Code:
@interface Globals
{
  Player *player;
}

Globals setup
{
  player = [Player init retain]; //etc...
}

Globals cleanup
{
  if (player)
  {
    [player release];
    player = nil;
  }
}

When my main code calls [Globals cleanup], I can verify that player gets released. However, the delloc method for the Player class is not getting called. There is no other place in my entire program that creates or retains the player object. It is only done in the Globals setup function, and I have verified by using NSLog messages that it is not being called more than once before the next cleanup.

Any thoughts and help are appreciated.

If I'm reading your shorthand correctly, you're doing this:

Code:
[[[Player alloc] init] retain];

Which is wrong. When you call alloc, the new object is allocated with a retain count of 1. Init does not change this. When you retain it again, its retain count is now 2.

If you don't retain it again, the problem should go away.

Consider re-reading Memory Management Programming Guide for Cocoa [developer.apple.com] again if you're unsure, and then try running the static analyser if you're using Clang - it can spot a lot of related reference counting errors.

Everyone's favourite forum lurker!
https://github.com/NSError
Quote this message in a reply
Nibbie
Posts: 1
Joined: 2009.11
Post: #3
Checking the value of [myObject retainCount] is often useful when you are having a problem like that.
Quote this message in a reply
Member
Posts: 73
Joined: 2009.03
Post: #4
Thanks for the replies. I swear I read that doing it this way didn't retain it, which is why you need to use autorelease if you wrap the alloc call in a convenience function. I'll check it out though.

[edit] I reviewed the doc. What I misunderstood is that if you return the new object without autorelease, then the reference pointer is lost but the object still exists in memory. That's messed up, but I get it now. I guess I better review all of my init code for all objects.
Quote this message in a reply
Member
Posts: 40
Joined: 2009.05
Post: #5
I find a good pattern to follow is to always do

MyObj *obj=[[[MyObj alloc] init] autorelease];

for local variables - the autorelease ensures the object will get cleaned up when you return the run loop (or any enclosing release pool).

And do

self.obj=[[[MyObj alloc] init] autorelease];

with a matching

self.obj=nil;

in my dealloc/cleanup.

where obj is a property declared with the retain attribute.

There are several unnecessary releases, retains, autoreleases going on, but the code is consistent and it's very hard to make a mistake.
Quote this message in a reply
Member
Posts: 144
Joined: 2009.11
Post: #6
iamflimflam1 Wrote:I find a good pattern to follow is to always do

MyObj *obj=[[[MyObj alloc] init] autorelease];

for local variables - the autorelease ensures the object will get cleaned up when you return the run loop (or any enclosing release pool).

And do

self.obj=[[[MyObj alloc] init] autorelease];

with a matching

self.obj=nil;

in my dealloc/cleanup.

where obj is a property declared with the retain attribute.

There are several unnecessary releases, retains, autoreleases going on, but the code is consistent and it's very hard to make a mistake.

I read in the Cocoa Performance Guidelines [developer.apple.com] that it is a good idea to minimize your use of the autorelease pool system. I think they're indicating that this:

Code:
- (id)runOperation {
    NSAutoreleasePool * pool0 = [[NSAutoreleasePool alloc] init];

    BigScaryObject * foo = [[BigScaryObject alloc] init];

    // do scary things

    [foo release];
    [pool0 release];
}

is better than simply autoreleasing BigScaryObject up front.

In reality, I seriously doubt the performance difference will be at all important, though I think it's a good thing to know if you're ever writing some code that needs to or should execute very quickly (say, in a very tight loop) that needs to use Cocoa frameworks.

Everyone's favourite forum lurker!
https://github.com/NSError
Quote this message in a reply
Member
Posts: 306
Joined: 2009.03
Post: #7
Another reason to minimize your autorelease is that autoreleased objects that cause a bug to happen are much harder to figure out because the function call won't come from your code but rather from apples code.
Quote this message in a reply
⌘-R in Chief
Posts: 1,256
Joined: 2002.05
Post: #8
cmiller Wrote:I read in the Cocoa Performance Guidelines [developer.apple.com] that it is a good idea to minimize your use of the autorelease pool system. I think they're indicating that this:

Code:
- (id)runOperation {
    NSAutoreleasePool * pool0 = [[NSAutoreleasePool alloc] init];

    BigScaryObject * foo = [[BigScaryObject alloc] init];

    // do scary things

    [foo release];
    [pool0 release];
}

is better than simply autoreleasing BigScaryObject up front.

In reality, I seriously doubt the performance difference will be at all important, though I think it's a good thing to know if you're ever writing some code that needs to or should execute very quickly (say, in a very tight loop) that needs to use Cocoa frameworks.


Mmmm... It's more like this...


Code:
{
    loop a billion times {
        NSSomething * blah = [NSSomething somethingEtc] (autoreleased)
        .... do more allocations and things ....
    }
}


That'll just eat gobs of memory which:
- Is inefficient in that it uses gobs more than it needs to
- Can be slow because of the time to actually allocate new memory to the app
- Can be gargantuanly slow because you can cause page outs when you eat sooo much memory you have to steal RAM from other processes.


The performance guidelines are suggesting:

Code:
{
    loop a billion times {
        NSSomething * blah = [[NSSomething alloc] init]
        .... do more allocations and things ....
        [blah release];
    }
}


You don't really need to avoid autorelease in any circumstances other than ones where you allocate a huge number of objects and there's no autorelease pool keeping memory usage in check constantly.
Quote this message in a reply
Member
Posts: 144
Joined: 2009.11
Post: #9
FreakSoftware Wrote:Mmmm... It's more like this...


Code:
{
    loop a billion times {
        NSSomething * blah = [NSSomething somethingEtc] (autoreleased)
        .... do more allocations and things ....
    }
}


That'll just eat gobs of memory which:
- Is inefficient in that it uses gobs more than it needs to
- Can be slow because of the time to actually allocate new memory to the app
- Can be gargantuanly slow because you can cause page outs when you eat sooo much memory you have to steal RAM from other processes.

I've always called that a "tight loop." My jargon might be off though. Sorry to confuse!

But we're both saying the same thing, which is good.

Everyone's favourite forum lurker!
https://github.com/NSError
Quote this message in a reply
⌘-R in Chief
Posts: 1,256
Joined: 2002.05
Post: #10
Re-reading what your last few sentences, yeah, you mentioned the tight loops. I kinda skipped over that the first time I read it and just saw your code block without a loop.
Quote this message in a reply
Post Reply 

Possibly Related Threads...
Thread: Author Replies: Views: Last Post
  removeFromSuperview not calling dealloc of view - SOLVED BeyondCloister 5 13,298 Aug 11, 2010 01:18 PM
Last Post: BeyondCloister