Objective-C memory issue (iPhone) - 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

Related

How to find the reference count of an object

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.

Do I have to release a NSLocalizedString?

The question is simple. Do I need to release a NSLocalizedString? For instance:
NSString *internetMessageTitle = NSLocalizedString(
#"You are currently not connected to a internet network"
#"Title of the message that tells the user there is no internet network");
Because I did this:
NSLog(#"Retain count of InternetMessageTitle is: %d",
[internetMessage retainCount]);
But it prints a retain count of 2. However I have read that the retainCount attribute is not very reliable. Should I release it twice?
And yes I have read the memory management rules and guide of the documentation but I don't see here any indication of NARC (NewAllocRetainCopy). I am still a beginner so I don't really know how NSLocalizedString makes strings.
Thank you!
EDIT1: I use this variable in a UIAlertView I don't know if the retainCount is increased there when I use it. And even when the alert is not used (inside an if, and if the if is skipped it isn't used) the retainCount is still 2 according to NSLog.
No, you must not release it. If you check how NSLocalizedString is defined you'll see:
#define NSLocalizedString(key, comment) \
[[NSBundle mainBundle] localizedStringForKey:(key) value:#"" table:nil]
That its normally a call to NSBundle's method that returns autoreleased string
I use this variable in a UIAlertView
I don't know if the retainCount is
increased there when I use it. And
even when the alert is not used
(inside an if, and if the if is
skipped it isn't used) the retainCount
is still 2 according to NSLog.
Yes, labels in UIAlert retain their content strings, but you should not worry about that - they will release them when get destroyed.
As you say, there's no NARC -- so you already know the answer is no.
And what you've read about retain counts? Heed it. Never look at the retain count as useful info. Never look at it all.
And FFS don't do something insane like calling release on an object several times just because you think it has a retain count > 1. That stuff is absolutely guaranteed to mess you up.
The Cocoa memory management rules are very simple. There's only one of consequence: all alloc/new*/*copy* calls must be balanced by a call to auto-/release. You're not calling a method or function named "alloc", starting with "new" or containing "copy", thus you shouldn't release.
Even simpler than following the memory rules is to use properties (object or class) when possible.

Memory leaks caused due to CoreFoundation Framework

I am developing an iPhone application which mainly makes use of the Address Book and database. After fetching about 3000 contacts from the address book, I am attaching string tags to the contacts (5 for each). I am saving my tags in the database.
For Load testing purpose i have added 10,000 tags to the App. But during the load testing of my application, I observed some memory leaks which were not related to the Application code but represents a set of Instruction sets. Also Instruments showed Foundation as the responsible library for the Leak (Extensive use of NSString,NSDictionary,NSArray which belongs to the Foundation framework). My application crashes after 10 - 15 mins of usage.The Crash report mentions, application crashed due to low memory.
Memory profiling using CLANG shows zero leaks. How do i solve these memory leaks?
Are these leaks the real culprit behind the crash? Are there any other tools available to check memory leaks?
I often find my leaks say they're caused by Core Foundation (or any other framework for that matter) but are really my own. With the exception of the Simulator, rarely will you find excessive leaking in the frameworks.
If you open up the detail panel to the right in Instruments you may find listed your App's methods in there. That will give you indication of where it could be coming from in your code. One leak can spring many other leaks, and you may have to find the top level culprit to get rid of the lower level ones.
You should not expect Clang to do anything but find the most obvious leaks. It's very handy, but that's it, just a helpful addition to compiling.
clang is not a leak checker. It only detects a small subset of issues.
For memory leak debugging you should focus on Instruments, specifically the Object Allocation and Leaks instruments. Be sure to understand the difference between leaks and other source of high memory usage though.
Once you've determined that objects are leaking, use Instruments to examine their allocation stack trace (so you can tell what object it is), and their retain/release history.
If it's not a leak, then I suggest investigating the instructions here:http://www.friday.com/bbum/2010/10/17/when-is-a-leak-not-a-leak-using-heapshot-analysis-to-find-undesirable-memory-growth/
Most likely you have code that is creating the foundation objects. Leaks shows you the place of allocation but that is generally due to a call your code made to create the object. You can look at the call chain in Instruments and go back along the call chain until you get to your code - that is the place where you are causing the allocation. Now, for that allocation, look at your memory handling for that object: Do you release it some time later?
There are lots of ways you can fail to release memory property so it would be hard to guess which one you might be hitting. Ones I see when helping people include allocating an object and assigning it to an instance variable via a property with the retain attribute, something like this:
#property (retain) NSString* myString;
...
self.myString = [[NSString alloc] initWithString: #"foo"];
the alloc+init creates a retained object, the self.myString = increments the retain count again. If coded correctly, the dealloc method releases the property via one of:
[myString release];
or
self.myString = nil;
And that takes care of the retain added with the self.myString = but does NOT take care of the retain from creation. Solutions, ONE of the following:
myString = [[NSString alloc] initWithString: #"foo"]; // doesn't call the setter method so no assignment retain - but doesn't call the setter which might be bad if non-trivial setter.
self.myString = [[[NSString alloc] initWithString: #"foo"] autorelease];
autorelease releases the alloc+init retain.
Now of course this is a contrived example because you'd probably really use:
self.myString = [NSString stringWithString: #"foo"];
which is a class method returning an autoreleased string and avoids the problem. But the idea is to show a simple example to explain this type of issue.
There are many other ways to not release memory properly, but the advice to work your way back up the call-chain until you get to your code is the way to go look at where you are triggering the allocation of the memory and then you can figure out why you aren't releasing that properly.
Try to do some issues in u code:
1. Please avoid hide declaration like
NSString *string = [dictionary valueForKey:[dictionary2 valueForKey:#"something"]]
Correct code is:
NSString *key = [dictionary2 valueForKey:#"something"];
NSString *string = [dictionary valueForKey:key];
key = nil;
Try to avoid declaration with autorelease and local declaration like:
NSArray *array = [NSArray array];
If u do this, make sure that u have:
NSArray *array = [NSArray array];
.... some code where array is using;
array = nil;
Better idea is alloc and release immediately when u don't need object and put it to nil.
3. Check if u using correct setters. Probably better idea is avoid to using it, at my experience, deallocate class start leaks for getters and setters, which was using before.
If u post some part of u code, where u seen most leaks (instruments give u possibility to click on leaked objects and see volume of leaks in programming code) community can suggest more.

calling [myString release] does NOT decrement [myString retainCount]

I have the following situation, which seems to cause my iPad application to leak memory.
I have a class with a string property...
#property(nonatomic,retain) NSString * synopsis;
I set the string property from some HTTP response, either from JSON or XML response.
At that point the retain count of the synopsis object is 1.
But I have this situation:
I save the synopsis to a local sqlite database, and then I want to release it from memory, but I have the situation where strangely, calling [synopsis release] from within my object does not decrement the retain count to 0.
(void) save
{
NSLog(#"synopsis before save retainCount=%d",[synopsis retainCount]);
[self saveToDb:synopsis withKey:#"synopsis"];
NSLog(#"synopsis after save retainCount=%d",[synopsis retainCount]);
[synopsis release];
NSLog(#"synopsis after release retainCount=%d",[synopsis retainCount]);
synopsis=nil;
}
In the console I get:
synopsis before save retainCount=1
synopsis after save retainCount=1
synopsis after release retainCount=1
How can this be possible? I get the same result running in simulator or on the device.
DON'T RELY ON RETAINCOUNT!
To humans, it's not an accurate measure of object ownership. You don't know what's calling retain and release behind the scenes in a framework.
Memory management in Cocoa is simple:
If you alloc/init or copy an object, make sure you call release on it at some point.
If you want to keep an object around, call retain -- but make sure to call release at some point, too.
Your third NSLog probably calls retainCount on a deallocated object.
The fact, that you see a value of 1 can have three reasons:
There's some other object at the same address now, that has a retain count of one.
(more likely) The deallocated object is still there. It responds to the message by returning the retain count, which would be one because it never was decremented to zero (no need to do that ever, since a deallocated object does not need a valid retain count).
The object is still there and has some custom memory management, preventing retainCount from being decremented.
Edit:
To check deallocation of objects (if you want to be sure), you could always override dealloc and set a breakpoint or put a log message there.
This might help. From the docs about retainCount:
Important: 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.
To understand the fundamental rules of memory management that you must abide by, read “Memory Management Rules”. To diagnose memory management problems, use a suitable tool:
• The LLVM/Clang Static analyzer can typically find memory management problems even before you run your program.
• The Object Alloc instrument in the Instruments application (see Instruments User Guide) can track object allocation and destruction.
• Shark (see Shark User Guide) also profiles memory allocations (amongst numerous other aspects of your program).

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