I'm trying to learn how instruments work, to do that i created a small project with a leak to see if it shows up in the Instruments but it's not showing up. The code i have to create the leak is the following:
-(IBAction)leakme
{
self.leaked = [[NSString alloc]init];
self.leaked2 = [[NSString alloc]init];
self.leaked3 = [[NSString alloc]init];
leaked = #"John";
leaked2 = #"Anderson";
leaked3 = #"Smith";
}
That doesn't show any leaks. As the application never reaches the dealloc method i did the following:
-(IBAction)nilit
{
self.leaked = nil;
self.leaked2 = nil;
self.leaked3 = nil;
}
But still no leaks are shown. What i'm i missing here?
Thanks.
You aren't actually causing anything to be allocated; NSString is optimized internally such that [[NSString alloc] init] returns a singleton.
Either use NSMutableString or use a class of your own creation (better).
Related
I have 100 images in my resource bundle named like image1.jpg,image2.jpg.
Basically what i am trying to do is create path names to those images dynamically inside a for loop.
While testing in simulator,the images loaded fine and the app did not crash.But while testing the app with instruments i was shocked to see the heavy memory leak that was happening while i was creating the path1 object.
I am pasting the entire method here for reference
- (id)init {
self = [super init];
if (self) {
self.arrayImages = [[[NSMutableArray alloc] init] autorelease];
for(int i=1 ; i<100 ; i++){
NSString *str = [NSString stringWithFormat:#"Century%d",i];
NSString *path1 = [[NSBundle mainBundle] pathForResource:str ofType:#"jpg"];
[self.arrayImages addObject:path1];
}
}
return self;
}
As i have not made use of any alloc inside the loop i dont have any ownership and hence no right to release the object.What is the reason for this memory leak??
Kindly explain the problem and provide the necessary solution in order to fix it..
As always,any help is highly appreciated..
arrayImages is retaining path1, and so if you do not release arrayImages it will leak. How are you creating arrayImages, and are you releasing it anywhere?
Edited based on comments:
Make sure you release arrayImages in your -dealloc method like so: [arrayImages release]; (note the lack of self).
There is no leak in the code you've shown.
There are (at least) two possibilities:
You have a leak in code you didn't paste into your question
Everything is fine and Instruments gave you a false-positive
Your loop will create a lot of autoreleased variables. These won't be deallocated until after the loop has finished, but that's how it's supposed to work.
The reason for the leak would be this line right here:
NSString *str = [NSString stringWithFormat:#"Century%d",i];
By using convenience methods in Objective-C, what happens in the background is the following:
NSString *str = [[[NSString alloc] initWithFormat:#"Century%d", i] autorelease];
Not using alloc/init to create a weak reference is a misconception. You are always the owner of a created object, no matter how you create it. The convenience method simply does the alloc/init and autoreleases it for you.
Here's what I would suggest you do to avoid leaking memory:
- (id)init {
self = [super init];
if (self) {
self.arrayImages = [[[NSMutableArray alloc] init] autorelease];
NSAutoreleasePool *tmpPool = [[NSAutoreleasePool alloc] init];
for(int i = 1 ; i < 100 ; i++) {
NSString *str = [NSString stringWithFormat:#"Century%d",i];
NSString *path1 = [[NSString alloc] initWithString:[[NSBundle mainBundle] pathForResource:str ofType:#"jpg"]];
[self.arrayImages addObject:path1];
[path1 release];
}
[tmpPool drain];
}
return self;
}
Let me know if this works better for you.
-EDIT- Allocating the path1 object and releasing it after adding to arrayImages.
According to the leak instrument in XCode it's saying this line is giving a memory leak (100%)?
self.unsentPatients = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
I'm correctly releasing etc. on dealloc (which is definitely being ran) so I don't understand where I am going wrong?
It's only a small leak and Analysis doesn't come up with anything, but nonetheless it's still a leak.
Kind regards,
Dominic
There are many things wring with this code.
I'm assuming that the property is retaining the value, then you should not assign the value the way you are doing now, but more like:
NSMutableArray *temp = [[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]];
self.unsentPatients = temp;
[temp release], temp = nil;
or
self.unsentPatients = [[[NSMutableArray alloc] initWithArray:[defaults arrayForKey:UNSENT]] autorelease];
You should also avoid using the self. syntax in dealloc or init, which will call a mutator.
In multithreaded environment this could give problems.
So the correct dealloc would be:
- (void) dealloc {
[unsentPatients release], unsentPatients = nil;
[super dealloc][;
}
Hi I generally create objects of another classes. can you please tel me if this wil be in the auto release pool? or should we release it manually.
if you init copy or new them you'll have to deallocate them if you put an autorlease with the allocation then they will be autoreleased
for example
Foo *foo = [[Foo alloc] init]; //you'll have release it somewhere yourself
And
Foo *foo = [[[Foo alloc] init] autorelease];// this will be autreleased
The simple case is : if you use init, you are responsible for releasing it, either by calling release or by calling autorelease.
e.g.
NSString *myString = [NSString alloc] init]; // You need to release this
...
[myString release]; // Now it's released - don't use it again!
or if you are going give it to someone else
NSString *myString = [NSString alloc] init]; // This needs releasing
...
return [myString autorelease]; // You are finished with it but someone else might want it
However, there's a few other cases.
NSString *myString = [NSString stringWithFormat:#"hi"];
This object is in the autorelease pool already - don't release it!
NSString *secondString = [myString copy];
This object needs releasing - it is not autoreleased.
Rule of thumb : Anything with init, copy or new in the name - you made it, you release it. Anything else will be autoreleased.
I'm trying to reduce the memory leaks in my app, so i used instruments to find all the leaks. I managed to remove almost all of the leaks, except a very annoying one.
Instruments is telling me that i have a lot of NSPlaceholderstring leaks.
The code that generated the leak (according to instruments) is:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
self.storedHash = description; // This line is the leak according to instruments
[description release];
description = nil;
}
return storedHash
storedHash is define like this:
#property(copy) NSString* storedHash;
I tried everything i can think of:
I used retain instead of copy
I used an autorelease allocation of the NSString (stringWithFormat)
I tried wrapping the code with an autorelease pool
Nothing of the above changed the leak. (In some cases the type of the leaks change, but there are still leaks)
Ideas anyone?
Where do you release storedHash? Do you release it in dealloc?
Note that NSPlaceholdeString is an implementation detail; it is the class of the instance returned by NSString's +alloc method.
How about in the dealloc method? Did you release the storedHash in the dealloc method? And how about checking if (nil == self.storedHash)
You should use
#property(nonatomic, retain) NSString* storedHash;
instead copy. #property(copy) didn't release your old NSObject and you should do it yourself:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
[self.storedHash release];
self.storedHash = description; // This line is the leak according to instruments
[description release];
// description = nil; // it's unnecessary
}
also you should release storedHash in dealloc.
If i try to use this simple code:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Add the tab bar controller's current view as a subview of the window
[window addSubview:tabBarController.view];
NSString *stringMer = [NSString stringWithFormat:#"OK COOL"] ;
NSString *stringMer2 = [NSString stringWithFormat:#"OK COOL"];
NSArray *truc = [NSArray arrayWithObjects:stringMer,stringMer2];
}
My application crashes ("unable to read unknown load command 0x22" or just a regular crash)... What the applicationDidFinishLaunching is from my FooAppDelegate and i have no more code, is this normal ?
The list of arguments passed to the arrayWithObjects: method must be nil-terminated:
NSArray *truc = [NSArray arrayWithObjects:stringMer,stringMer2, nil];
Don't use +stringWithFormat: unless you actually have a format string that needs parsing.
NSResponder is right - don't get sloppy by defaulting to stringWithFormat.
Perspx also pointed out a fairly obvious (but easily forgotten) error with the missing nil.
I'd be a bit more explicit -
(in the .h)
NSArray *truc; (assuming it won't be a property)
(in the .m)
//actually, I'd define, "OK COOL" as a string and init with that, but...
NSString *stringMer = [[NSString alloc] initWithString:#"OK COOL"] ;
NSString *stringMer2 = [[NSString alloc] initWithString:#"OK COOL"];
truc = [[NSArray alloc] initWithObjects:stringMer,stringMer2, nil];
//appease the memory gods
[stringMer release];
[stringMer2 release];
(then, down in dealloc)
[truc release];
It would be good to get really familiar with Instruments - run for Leaks.