How to find the reference count of an object - iphone

I want to know the reference count of an object in my program. Can I?

Sure:
int referenceCount = rand();
The real answer, of course, is the retainCount method; NSUInteger rC = [someObject retainCount];. However, the value returned by it is useless.
never never use the retain count in a conditional
the retain count can never be zero
the retain count never reflects whether or not the object is autoreleased
a retain count of 2-bazillion is perfectly reasonable for some classes some of the time
the retain count for any object that passes through system API may be a seemingly random value within indicating a problem
Bottom line: If you treat the retain count as an absolute value, you are doing it wrong. You either increase or decrease the retain count through your code, Keep your plusses and minuses in balance, and you are doing it right.

You can, but you are wrong: you don't want to do that.

Isn't it meant to be...
[obj retainCount];

Never use retainCount, it does not work the way you think it does.
See: SO on finding retains/releases

As everybody said, you can, BUT DON'T USE IT.
Back when I started I also thought that using the ref count I could find my memory problems easier. I wasted TOO MUCH time. The number you get is simply wrong in the sense that you can not (easily) just use it to find your memory management issues.
It is by far better to really check all the manually created objects with alloc, new, and your manual retains.
Simply sit back and focus onthe question "Who has ownership of this variable?" All thouse will keep your var alive. Also be sure to set your ivars with self.ivar, otherwise the ownership to the object will not be set.
But the easiest is to just use ARC in the newest version. This takes care of (most) of all these questions....

Not sure why all the posts about not using retainCount, its been valuable in tracking down memory issues for me, now I wouldn't use it as a conditional, nor even understand how that would even be used, but you can add a simple category and use retain count adequately to determine lifetime usage of any given class.
#implementation replaceWithYourClassName (MemoryInspecting)
- (id) retain
{
NSLog(#"RETAIN: self [%#] : retain count [%d]", [self description], [self retainCount]);
return [super retain];
}
- (void) release
{
NSLog(#"RELEASE: self [%#] : retain count [%d]", [self description], [self retainCount]);
[super release];
}
And throw some breakpoints in there to track the context if that helps, as it often does.

Related

Ignore 'Object sent -autorelease too many times" warning

When running Analyzer, I receive the "Object sent -autorelease too many times" warning. I know I'm doing something tricky (and am open to alternatives to accomplishing my goal).
Essentially, I wanted to keep a stack of specific types of controllers handy for sending messages from a central location. So, considering:
From 'ActionBroker' shared object:
NSMutableSet *liveActions;
liveActions = [NSMutableSet alloc] init];
...
CLViewController *action = [[[actionClass alloc] init] autorelease];
if (!action) {
return nil;
}
[self.liveActions addObject: action];
// When adding an object, the retain count is increased. We want the action
// to dealloc, so that it might remove itself from the list...
[action release];
return action;
And the complementary dealloc code:
[[CLActionBroker sharedActionBroker] removeAction: self];
[super dealloc];
... and in removeAction:
[action retain];
[self.liveActions removeObject:action];
The above code works, I just get the nagging error. And the nagging sensation that I could probably solve the problem a different way.
One of the use cases for this code is to pass an 'handleOpenURL' request through a chain of open controllers and returning the first 'YES' response.
As I understand it, your intent is to have a set of controllers ("actions") in the set, which you could easily access from anywhere in your app. If one of these controllers is deallocated, it would automatically remove itself from the set.
There's a problem with this setup, though. As you've described it above, the controller is supposed to be removed from the liveActions set upon deallocation. But since an NSSet retains its members, your controller will never be deallocated so long as it is still in the liveActions set. -dealloc is only run when all retains have been balanced by a release.
This, then leads to your over-release, which leads to the warning. Since you've sent an extra release, -dealloc could be run while the controller is still in the liveActions set. But when you remove it from that set, it's going to send a release message to your object, which would take its retain count negative. That may or may not be safe, but in either case it's an ugly workaround.
What you really want, it seems, is a set that does not retain its members. This is normally a dangerous configuration, since it can lead to dangling pointers in the set. But if you're willing to manage the lifetime of the object and clear out those dangling pointers at the appropriate times, it turns out that it's quite doable. You just need to use a CFMutableSet instead of an NSMutableSet. And since the two are toll-free bridged, it doesn't even add that much complexity.
Setting up the CFMutableSet looks like this:
// The NULL for the third parameter tells the set to not do anything when
// an object is added to or removed from the set.
CFMutableSetRef cfLiveActions = CFSetCreateMutable(NULL, 0, NULL);
// Toll-free bridging makes this possible
NSMutableSet *liveActions = (NSMutableSet *)cfLiveActions;
After that, you can use it exactly as you would use any other NSMutableSet; this one will just be special in that it won't retain its members.
The problem:
CLViewController *action = [[[actionClass alloc] init] autorelease]; // +0 ownership
// ...
[self.liveActions addObject: action]; // liveActions takes ownership
// ...
[action release]; // -1 ownership
When you've alloced the object, you are responsible for it. But then when you autorelease it, you've fulfilled your obligation (and because you autoreleased instead of releasing, you can still use the object until the next turn of the runloop). You shouldn't release it again later.
Also:
[action retain];
[self.liveActions removeObject:action];
The retain is unnecessary.
(And here's another plug for beginning to switch to ARC, under which you won't have to worry about this!)
[Edit: misunderstood your question. Revised answer forthcoming.]
[Edit 2: never mind... even though I misread your intent, I believe my solution is still right.]

Why is the retainCount still 1 after [object release]?

NSLog(#"first:%u",[object retainCount]);
[object release];
NSLog(#"second:%u",[object retainCount]);
Output:
first:1
second:1
Why doesn't the object get released?
a Quote from NSObject reference on retainCount method
This method is typically of no value
in debugging memory management issues.
Because any number of framework
objects may have retained an object in
order to hold references to it, while
at the same time autorelease pools may
be holding any number of deferred
releases on an object, it is very
unlikely that you can get useful
information from this method.
Object can be released but not when you think it will be. Basically, don't look at retainCount. It may not change until the next runloop or at all, it's an implementation detail. You will get a sense for when you need to release and when you don't with experience but until then rely on the clang analyzer.
First, retainCount doesn't give you a number you can use. It's meaningless.
Second, the reason the retainCount is 0 is probably that you try to work with an object that doesn't exist anymore. You're lucky your application doesn't crash, because your accessing invalid memory. Decreasing the retainCount just before deallocating an object is unnecessary, therefore Apple doesn't do it, probably.
Divide any number by zero and you will find the meaning of "object with retain count of zero".
I agree with the other comments about not using retainCount to get a reliable count.
EDIT: Ignore my stupidity below... :)
However, I've observed that setting the corresponding property to nil...
self.object = nil;
the retainCount does tend to be decremented immediately.

Is release without prior retain dangerous?

I have some code which I think has extra release statements.
Is the code incorrect?
What is the end result?
I don't understand memory management well yet - even after reading lots of articles and stackoverflow answers. Thanks for straightening me out.
Update: The attached snippet works fine, but other code has the over-release problem
NSMutableArray *points = [NSMutableArray new];
for (Segment *s in currentWorkout.segments) {
[points addObjectsFromArray:[s.track locationPoints]];
}
[routeMap update:points];
[points release];
Your code is correct, but inadvisable. new acts as an implied alloc, which creates the object with a retain count of 1.
I think the last time I used new was in 1992; it's not wrong, but alloc/init is considered better practice, because it is clearer what you are doing. Please read Apple's guide to memory management, it is a comprehensive summary of the situation.
No messages can safely be sent to a deallocated object. Once an object has been released a sufficient number of times, it's deallocated. Any further messages sent to that object are going to an object that isn't there anymore. The precise result isn't completely predictable, but it usually ends in a crash. If you're less lucky, it could end in much stranger ways — for example, you could theoretically wind up with an Object A getting dealloced early and Object B allocated in the same memory location, then Object B receiving messages meant for Object A that Object B does understand but isn't supposed to receive at that time.
Basically, follow the rules. Think of it in terms of ownership. If you've claimed ownership, you need to release that ownership. If you don't own the object, you must not release it.
Take a look at this article online: http://weblog.bignerdranch.com/?p=2 .
It seems to imply that calls to release without a corresponding preior call to retain will result in a BAD_ACCESS error.
A short answer is, if you increasing the retain count of an object and you no longer are using it you should release it, otherwise you shouldnt...
So when ever you do a [objectName alloc] you are increasing the count by 1, when you use such methods as [NSString stringWithString:] these methods return an autoreleased object so you dont need to release it...if you instead did something like [[NSString stringWithString:]retain] then you are increasing the strings retain count and you should release it after you are done using it.
Im not too sure if new increases the reference count (i suspect that it would), you can always check your retain count by doing [object retainCount]... though note that even if the retain count is greater than 0, it does not mean you need to release the object, because some other class might have a reference to the object and therefore has its retain count increased by one and its the responsibility of the other class holding the reference to release it.
Hope this helps
you should use:
NSMutableArray *points = [[NSMutableArray alloc] init];
[...]
[routeMap update:points]; //if routemap stores the points, it will need it's own release retain
[points release]; //if there is a retain in the method above, reference will not be cleared
if unsure, use the build->analyze command, it will search your code for leaked references
you can get the official memory management guide from https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html

Objective-C memory model

I am attempting to wrap my head around one part of the Objective-C memory model (specifically on the iPhone, so no GC). My background is C/C++/Java, and I am having an issue with the following bit of code (also wondering if I am doing this in an "Objective-C way" or not):
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [NSMutableSet new];
// would normally fill the set in here with some data
return ([set autorelease]);
}
- (void) test
{
NSSet *setA;
NSSet *setB;
setA = [self retrieve];
setB = [[self retrieve] retain];
[setA release];
[setB release];
}
start EDIT
Based on comments below, the updated retrieve method:
- (NSSet *) retrieve
{
NSMutableSet *set;
set = [[[NSMutableSet alloc] initWithCapacity:100] autorelease];
// would normally fill the set in here with some data
return (set);
}
end EDIT
The above code gives a warning for [setA release] "Incorrect decrement of the reference count of an object is not owned at this point by the caller".
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
From what I have figured out by trial and error, setB is correct, and there is no memory leak, but I'd like to understand why that is the case (what is wrong with my understanding of "new", "autorelease", "retain", and "release").
I though that the "new" set the reference count to 1. Then the "retain" call would add 1, and the "release" call would drop it by 1. Given that wouldn't setA have a reference count of 0 at the end and setB have a reference count of 1 at the end?
You're leaving out the autorelease. When -(void)test gets a set, its retain count is 0. You don't retain setA, so it already has a retain count of 0 when you try to release it, hence the error message.
The fundamental rule for memory management is quite simple: calls to alloc, new and copy* must be balanced by calls to release/autorelease. The former take ownership, the latter relinquish ownership.
The only tricky part is when dealing with shared objects, where you don't take ownership of an object, so it might be discarded in between the time you get a reference to it and when you use it. This has a simple solution: if in doubt, retain it.
You can make things even simpler by using properties in many situations.
Don't think in terms of absolute numbers. That can be very deceptive. Think of retains and releases as deltas if you must have a number — in this case, the autorelease has already balanced the new (a +1 delta and a -1 delta), so that method manages its memory correctly and the receiver doesn't need to do anything unless it wants to keep the object around longer.
Definitely read the memory management docs. It really is as simple as following the rules described there. It's a very simple contract of ownership where you claim ownership when you want an object to stick around and relinquish ownership when you don't care anymore. In the case above, you relinquish ownership in the retrieve method, so trying to relinquish ownership when you don't have it is obviously a bug.
As the profiler message hints, you should be thinking in terms of ownership. As noted in the memory management rules, whenever you have an object that you have created with +alloc, +new, -copy, or -mutableCopy, you own it and are responsible for releasing it eventually. (In fact, +new is just shorthand for [[MyClass alloc] init].)
-retain takes an object that you didn't initially own and makes you own it.
-release takes an object that you own and releases ownership of it.
-autorelease takes an object that you own and releases ownership of it, but also guarantees that the object will exist for at least a little bit longer.
Your -retrieve method does not transfer ownership of the object it returns. This is good—it follows the memory management rules (the method isn't +alloc, +new, -copy, or -mutableCopy). Therefore, using -release on it without using -retain is an error. It would be equally valid to not retain or release the result from -retrieve, as long as the object will have a temporary lifetime—your -autorelease guarantees temporary existence of the object.
http://www.macresearch.org/difference-between-alloc-init-and-new
You probably want
NSMutableSet *set = [[NSMutableSet alloc] initWithCapacity: someNumber];
or
NSMutableSet *set = [NSMutableSet setWithCapacity: someNumber];

Objective-C memory issue (iPhone)

I'm somewhat confused by the following behavior I'm seeing within an Xcode project compiled for the iPhone simulator (or device):
NSString *test = [[NSString alloc] initWithCString:"foo"];
NSLog(#"test retain count = %d", [test retainCount]); // prints 1
[test release];
NSLog(#"test retain count = %d", [test retainCount]); // also prints 1 instead of 0
However, any further attempts to access 'test' result in a crash of the Xcode enviroinment, whether it be another [test retainCount] NSLog statement or otherwise (even if only to check if test is equal to nil).
Thoughts? Compiled within a simple View based test project...code exists within project's applicationDidFinishLaunching method.
Clarification -- I know NOT to do the above in practice. This was just a test to see why in some debugging cases a retain count of 1 wasn't actually reflecting the real state of an object. Thanks for your responses. This was just a test stub to see why I was seeing certain behavior in a few cases. What I'm really trying to do is track down a very small memory leak (0.06MB) that is consistently being created whenever I destroy/recreate a custom view.
Retain counts are a debugging aid and can be misleading based on what Cocoa may be doing behind the scenes. This is particularly true with string literals where the data is permanently available and is never really deleted.
Concentrate of ensuring your code follows the Cocoa memory management rules with respect to object ownership. Where necessary, use Instruments to check for actual memory leaks.
You are calling retainCount on test after it has been released and possibly deallocated, so definitely the result is not reliable, not to mention you shouldn't be sending dealloced objects any messages.
Don't rely on retain counts...the framework may be retaining stuff on its own.
Instead, rely on the rules of memory management for objective-C. If you alloc, init, or new something, you own it and are responsible for releasing it. If you didn't, you aren't.
don't rely on the retain count; instead, make sure that you're balancing retains and releases. Here are some links on Cocoa (Touch) memory management:
http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
When you send that release, the string is dealloced — it has no other owners retaining it. Sending further messages to it (including retainCount) is an error and won't return anything meaningful.
And as others have pointed out, don't rely on retain counts to be particularly useful. They're a piece of the picture you can look at, but they're often misleading. For example, autoreleases don't show up in the retain count, sometimes objects are retained extra times for caching purposes, etc. In this particular case, though, you're not sending the message to a valid object at all, so you're lucky to get back an answer rather than a crash.
You should read Apple's memory management guide if you're unclear on any of this. It's not too complicated and absolutely essential for programming Cocoa.
One trick to improve the code shown above would be to use the 'set to nil' convention.
EG:
NSString *test = [[NSString alloc] initWithCString:"foo"];
NSLog(#"test retain count = %d", [test retainCount]); // prints 1
[test release];
test = nil; // set to nil, as I have released the pointer, I should no longer use it.
NSLog(#"test retain count = %d, test foobarpro = %d", [test retainCount], [test foobarPro]); // will now print 0 and 0 - because any objective-c call on a nil object returns 0 (and will not crash)
By setting a pointer to zero after you release it, you future proof your code a little: Someone coming along later and editing code 10 lines below can accidentally use 'test' with likely no ill effects (or an obvious crash). I even set pointers to nil in dealloc calls, as some of the hardest debugging tasks happen when non - nil 'bad' pointers are used in destruction.
Also you can debug with zombies to look for cases where you use pointers like your invalid test.
--Tom