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.
Related
When profiling the SimpleEKDemo application from Apple I note there are some memory leaks.
One of the leaks is __NSArrayM which has 3 lines in the Leaked Blocks history, a Malloc/Assign/Release.
Question - can someone point out the root cause issue here? (I'm trying learn how to take Instruments output of where a leaky object was created, and then from there work out root cause, so this would be really useful)
You will notice that when you run the demo with leaks that there is a leak in viewDidLoad (responsible frame). If you switch to Call Tree detail and if you have enabled Invert Call Tree, you will see a leak associated with the call +[NSArray new]. If you open that a bit, you will see initWithArray which is called in the RootViewController's viewDidLoad. The problem bit is,
self.eventsList = [[NSMutableArray alloc] initWithArray:0];
eventsList is a retained property so the object created has a retain count of 2. However it is only released once either through the release in dealloc or through reassignment of eventsList. YOu will have to autorelease this object.
self.eventsList = [[[NSMutableArray alloc] initWithArray:0] autorelease];
Once fixed, you shouldn't get any errors.
I am working on an app that imports a (very) large csv file into Core Data for catching purposes. The process goes something like this:
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
Rinse and repeat
At first glance it looks like the memory should be freed up at the conclusion of each cycle. With large files, however, I am finding that the app crashes after signaling a couple low memory warnings. Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
I understand that NSString are reused whenever possible, and that they don't act quite the same as other objects where memory is concerned, although I don't understand any of the details. How can I reclaim the memory that my NSString objects are using?
Running the leaks tool tells me that most of the memory is being used up by CFString objects, which I understand are related to NSString objects (although I don't know how)
NSString is actually a class cluster. Although you think you are working with NSStrings, you are almost certainly really working with one of its subclasses. The Cocoa framework chooses which subclass to use depending on circumstances.
CFString is actually not really an NSString at all, it is the pure C string object used by Core Foundation. However, you'll find it is "toll free bridged" to NSString. This means that, to Cocoa, it looks like an NSString. The reason you are seeing lots of CFString usage is because whatever Cocoa API you are using to obtain these strings ultimately performs its work in Core Foundation.
Anyway, all that is irrelevant to your problem except for the fact, that lots of CFStrings more or less means the same as lots of NSStrings. What you need to reduce your memory footprint is nested autorelease pools as Girish has already said. As a first step, modify your algorithm like this:
Create a new autorelease pool.
Parse the file line-by-line into an NSMutableArray full of NSStrings
After X number of lines, import the array into Core Data (this involves manipulating and in some cases creating new NSStrings)
[NSMutableArray removeAllObjects];
drain the autorelease pool
Rinse and repeat (start at 0)
If this doesn't help, or only helps a bit, consider bracketing just the parsing with an autorelease pool.
I am assuming that you don't have memory leak.
If you are using too much autoreleased object this can happen
You try following
Create nested auto release pools --- some time happen that you have some long running loops where auto release object get accumulated. -- so add custom auto release pool to release the auto release object when you required.
Don't use autorelease object in the parsing cycle --- do manual object allocation and release once your work is done.
You can't sure that the memory is consumed by NSStrings only. I suggest you check it thoroughly. Try to go for "Build and Analyze" it will help you to find out leaks.
While using NSString object, instead of going for autoreleased objects like
[NSString stringWithFormat#""];
create your own object and release it as soon as you done with it.
NSString * string = [[NSString alloc]initWithFormat:#""];
//use string object
[string release];
this way you can be sure, that you releasing the string there itself.
or create an Autorelease pool
NSAutoReleasePool * pool = [[NSAutoReleasePool alloc]init];
// do you coding, creation of objects, releasing them, whatever...
[pool drain]; or [pool release];
Also have a look at these memory management tips
Hi I am getting memory leak in Instruments for the following line of code .
NSArray *itemsList=[[NSArray alloc] initWithObjects:#"Love",
#"Hate",#"Happy",#"Sad",
#"Desire",#"Anger",#"Hope",#"Fear",#"Silly",nil];
I am using the below code:
arrayList is also released in dealloc block.
NSArray *itemsList=[[NSArray alloc] initWithObjects:#"Love",#"Hate",
#"Happy",#"Sad",#"Desire",
#"Anger",#"Hope",#"Fear",#"Silly",nil];
self.arrayList=itemsList;
[itemsList release];
I'm assuming that arrayList is declared using retain in the #property statement. If not, then that is certainly your problem.
If it is, then you have a leak, but not in the code you've posted. It's important to realize that Instruments first shows not necessarily where the leak occurred, but where the leaked memory was allocated. You'll have look through the rest of your uses of arrayList and find where you have a retain that's missing a release.
If you click on the arrow next to the memory address of the object in Instruments, you should be able to see everywhere that your object was retained and released. You'll have look through them and identify which retain is missing a release.
In my own iPhone Application I have used a number of nsstring variables to store values. But sometimes its value becomes Invalid! Does anybody know what may be the reason? Or tell me about the situation when a nsstring variable becomes Invalid?
NSStrings are also objects. They go by the same memory management rules. If you sin against those rules you will get a pointer to invalid memory and it will look like "invalid" data.
For example:
myString = [NSString stringWithString:#"foo"];
This will create an NSString* that's got autorelease on. When you're assigning it to an ivar that autorelease pool will soon pop putting the retain count back to 0 and dealloc'ing it while you still have a reference to it!
Naughty.
Instead, either retain it or use:
myString = [[NSString alloc] initWithString:#""];
This returns an owning reference. Remember to [myString release]; in dealloc.
This is just one example/case of bad memory management. Read the docs on how to properly manage your object lifecycle. Really.
They are being autoreleased. If you create a string using a convenience method (stringWithString, stringWithFormat) it will be added to the autorelease pool.
To stop it being released automatically, sent it a retain message and a release message when you have finished using it so that the memory is released. You can also set up properties to do this semi automatically when you assign the string to a member variable
There are a lot of articles on iPhone (and Mac) memory management here on SO and on the interwebs. Google for autorelease.
If this is for a device with fairly limited resources such as the iPhone, you should use [[NSString alloc] init*] over the static convenience methods, as you will put less pressure on the autorelease pool and lower your memory usage. The pool is drained every message loop, so the less objects to enumerate the better.
You should also be aware that autorelease objects in a loop will generate a lot of garbage unless you manage a local autorelease pool.
did you copy or retain the NSString ?
I asked the same question. And the following answer was the best of convenience. Just use:
[myString retain];
And then in dealloc method (e.g. viewDidUnload):
[myString release];
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