Advertise Books Events Forum News Social Networking Support Us

sdkIQ for iPhone
($4.99)

Shape Up
($0.99)

Your First iPhone App
($1.99)

iVidCam Free
(free)

Kid Art
($0.99)

iPUBQUIZ
(£1.19)

ArtStudio
($3.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 07-02-2009, 02:03 PM   #1 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default Memory Leaks..!

Hello Everyone,
I have been trying my application on Instruments and it is giving memory leak

Event Type : Malloc
Responsible Library : Foundation
Responsible Caller : -[NSPlaceholderString initWithBytes:length:encoding:]

Any ideas what is causing this?


Thanks,
Mubashir
_mubashir is offline   Reply With Quote
Old 07-02-2009, 02:24 PM   #2 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
Default

Quote:
Originally Posted by _mubashir View Post
Hello Everyone,
I have been trying my application on Instruments and it is giving memory leak

Event Type : Malloc
Responsible Library : Foundation
Responsible Caller : -[NSPlaceholderString initWithBytes:length:encoding:]

Any ideas what is causing this?


Thanks,
Mubashir
At the bottom of the instruments panel is a "detail" button that will pop up an extra pane on the right side of the window. If you click on your leak, this detail pane will display the stack trace at the time the object was created. You should see some of your own methods in that pane, which should help you narrow down where the object is being created.
__________________

Last edited by smasher; 07-02-2009 at 02:29 PM. Reason: rm purple - color depends on depth
smasher is offline   Reply With Quote
Old 07-02-2009, 02:41 PM   #3 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

Thanks for the reply..
I think I have found the leak - It comes up after calling the function which I use to get data from my sqlite db. here is the code

Code:
while (sqlite3_step(statementSelectProvider) == SQLITE_ROW) {
		
		int iD = sqlite3_column_int(statementSelectProvider, 0);
		NSString *PID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 1)];
		NSString *LName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 2)];
		NSString *FName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 3)];
		BOOL isNew = sqlite3_column_int(statementSelectProvider, 4); 
		NSString *city = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 5)];
		
		Provider *objProvider = [[Provider alloc] initWithTitle:iD ProviderID:PID LastName:LName FirstName:FName city:city isNew:isNew];
		[appDelegate addProvider:objProvider];
		
		
		[objProvider release];
		
		
	}

Can you see any leak?


thanks,
Mubashir
_mubashir is offline   Reply With Quote
Old 07-02-2009, 03:35 PM   #4 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 338
Default

It's probably something in that Provider class, are you creating something there that you aren't releasing?
lukeca is offline   Reply With Quote
Old 07-02-2009, 03:49 PM   #5 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
Default

Perfect. The trace shows you where these objects were created, which is great. I suspect that the real problem is with the "Provider" class - it probably retains these strings (or puts them in "retain" properties) and never releases them.

Does the "Provider" class have a dealloc method? It probably should, and it should look something like this:

Code:
- (void)dealloc {
    [name release];
    [lastname release];

     self.city=nil;  //this is the same as [city release] if city is a "retain" property.

	[super dealloc];
}
That way, all of the objects retained by the provider can b released when the provider is deallocated. That [super dealloc] is one of the few times that you call dealloc yourself instead of just release.
__________________
smasher is offline   Reply With Quote
Old 07-03-2009, 01:34 AM   #6 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

I see....I have dealloc in my Provider class and I am not declaring retain properties. Here is what I have
Code:
property(assign, nonatomic) int ProviderMasterWK;
@property(copy, nonatomic) NSString *ProviderID;
@property(copy, nonatomic) NSString *LastName;
@property(copy, nonatomic) NSString *FirstName;
@property(copy, nonatomic) NSString *City;
Here is the initializer
Code:
-(id) initWithTitle:(int)iD ProviderID:(NSString*) PID LastName:(NSString*)LName FirstName:(NSString*)FName city:(NSString*)city isNew:(bool)bNew
{
	if (self = [super init]) {
		ProviderMasterWK = iD;
		self.ProviderID = PID;
		self.LastName = LName;
		self.FirstName = FName;
		self.City = city;
		bIsNew = bNew;
	}
	
	return self;
}
And here is the dealloc

Code:
- (void)dealloc {
    [ProviderID release];
    [LastName release];
    [FirstName release];
	[City release];
	self.ProviderID = nil;
	self.LastName = nil;
	self.FirstName = nil;
	self.City = nil;

    [super dealloc];
}

What is going wrong I wonder

Appreciatively,
Mubashir
_mubashir is offline   Reply With Quote
Old 07-03-2009, 02:45 AM   #7 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
Default

Hmmn. You should use [ProviderID release] or self.ProviderID = nil, but not both. Using both will probably cause the object to be released too many times. That's the opposite of the problem you're having, though.

I do not see the leak in any of the code you posted. However, if you open the details pane in the Leaks instrument you should be able to see the stack track for the object that's being leaked. You'll see some of your methods in the stack, and you should be able to double-click the stack frame to find the exact line where the object is being created. Know which object it is may help you find where it leaks.

PS does the leak happen right after you load the data, or after you make changes to the data in memory?
__________________
smasher is offline   Reply With Quote
Old 07-03-2009, 03:32 AM   #8 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

Hi,
The leak happens right after ViewDidLoad->getData functions.
So my viewDidLoad calls getData which fetches the data from sqlite DB and create Provider Objects and stores them in a NSMutableArray declared in the appdelegate. Here is complete function

Code:
- (void)getData {
	  
	MRAAppDelegate *appDelegate = (MRAAppDelegate *)[[UIApplication sharedApplication] delegate];
		if(statementSelectProvider == nil){
		const char *sql = "SELECT ProviderMaster_WK, ProviderID, LastName, FirstName, IsNew, City FROM tblProvider WHERE Project_WK=?";
		if (sqlite3_prepare_v2(database, sql, -1, &statementSelectProvider, NULL) != SQLITE_OK)
		{NSAssert1(0, @"Failed to prepare database with message '%s'.", sqlite3_errmsg(database));}
		// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
		// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.   
	}

	sqlite3_bind_int(statementSelectProvider, 1, appDelegate.ProjectWK);
	
	// We "step" through the results - once for each row.
	while (sqlite3_step(statementSelectProvider) == SQLITE_ROW) {
		// The second parameter indicates the column index into the result set.
		int iD = sqlite3_column_int(statementSelectProvider, 0);
		NSString *PID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 1)];
		NSString *LName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 2)];
		NSString *FName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 3)];
		BOOL isNew = sqlite3_column_int(statementSelectProvider, 4); 
		NSString *city = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 5)];
		
		Provider *objProvider = [[Provider alloc] initWithTitle:iD ProviderID:PID LastName:LName FirstName:FName city:city isNew:isNew];
		[appDelegate addProvider:objProvider];
		
	
		[objProvider release];
		
		
	}
	
	// "reset" the statement 
	
	sqlite3_reset(statementSelectProvider);
	if(statementSelectProvider)
	{
		sqlite3_finalize(statementSelectProvider);
		statementSelectProvider=nil;
	}
}
Please suggest if anything is wrong

Thanks,
Mubashir
_mubashir is offline   Reply With Quote
Old 07-03-2009, 03:38 AM   #9 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

And Here is the addProvider function that adds in a Provider object into the NSMutableArray. This is in appdelegate

Code:
- (void)addProvider:(Provider *)provider{
	
	if(arrProvider == nil)
	{
		NSMutableArray *Array = [[NSMutableArray alloc] init];
		self.arrProvider = Array;
		[Array release];
	}
    [arrProvider addObject:provider];
}
_mubashir is offline   Reply With Quote
Old 07-03-2009, 11:14 AM   #10 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
Default

Put a breakpoint or NSLog in Provider's dealloc method; maybe it is never being called. I assume you're releasing arrProvider in your appdelegate's dealloc method? Or is that leaking too?

Also, if you click the gray arrow next to the address of your leaked NSPlaceholderString you can see that "history" of that memory address. Start at the bottom (most recent) and look up until you see malloc. That will be the history of every time that object was malloc'd, retained, and released. Somewhere in there is a retain without a release.

PS - I am able to create a similar leak in my own code if I modify ProviderID, LastName, or FirstName directly, without using "provider.blah = blah" or "self.blah = blah". Are you, in any location, changing the variable without using the property?
__________________

Last edited by smasher; 07-03-2009 at 11:24 AM. Reason: add PS
smasher is offline   Reply With Quote
Old 07-03-2009, 11:30 AM   #11 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 11
Default

Quote:
Originally Posted by _mubashir View Post
Hi,
The leak happens right after ViewDidLoad->getData functions.
So my viewDidLoad calls getData which fetches the data from sqlite DB and create Provider Objects and stores them in a NSMutableArray declared in the appdelegate. Here is complete function

Code:
- (void)getData {
	  
	MRAAppDelegate *appDelegate = (MRAAppDelegate *)[[UIApplication sharedApplication] delegate];
		if(statementSelectProvider == nil){
		const char *sql = "SELECT ProviderMaster_WK, ProviderID, LastName, FirstName, IsNew, City FROM tblProvider WHERE Project_WK=?";
		if (sqlite3_prepare_v2(database, sql, -1, &statementSelectProvider, NULL) != SQLITE_OK)
		{NSAssert1(0, @"Failed to prepare database with message '%s'.", sqlite3_errmsg(database));}
		// Preparing a statement compiles the SQL query into a byte-code program in the SQLite library.
		// The third parameter is either the length of the SQL string or -1 to read up to the first null terminator.   
	}

	sqlite3_bind_int(statementSelectProvider, 1, appDelegate.ProjectWK);
	
	// We "step" through the results - once for each row.
	while (sqlite3_step(statementSelectProvider) == SQLITE_ROW) {
		// The second parameter indicates the column index into the result set.
		int iD = sqlite3_column_int(statementSelectProvider, 0);
		NSString *PID = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 1)];
		NSString *LName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 2)];
		NSString *FName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 3)];
		BOOL isNew = sqlite3_column_int(statementSelectProvider, 4); 
		NSString *city = [NSString stringWithUTF8String:(char *)sqlite3_column_text(statementSelectProvider, 5)];
		
		Provider *objProvider = [[Provider alloc] initWithTitle:iD ProviderID:PID LastName:LName FirstName:FName city:city isNew:isNew];
		[appDelegate addProvider:objProvider];
		
	
		[objProvider release];
		
		
	}
	
	// "reset" the statement 
	
	sqlite3_reset(statementSelectProvider);
	if(statementSelectProvider)
	{
		sqlite3_finalize(statementSelectProvider);
		statementSelectProvider=nil;
	}
}
Please suggest if anything is wrong

Thanks,
Mubashir
As a good practise you should also release your bindings (see Reset All Bindings On A Prepared Statement). I think the libsqlite3 will not release all resources as long the bindings are still active. Anyway sqlite3 is a "plain c" lib so it will not work with objective-c memory management. But maybe this helps

Carsten
hcarsten is offline   Reply With Quote
Old 07-03-2009, 01:13 PM   #12 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

Quote:
Originally Posted by smasher View Post
Put a breakpoint or NSLog in Provider's dealloc method; maybe it is never being called. I assume you're releasing arrProvider in your appdelegate's dealloc method? Or is that leaking too?
I have put NSLog in dealloc and it gets called fine. Yes I am releasing arrProvider (NSMutableArray) in the appdelegate's dealloc. I am getting leak on Provider object as well so I assume its leaking. One thing I need to know is I have arrProvider filled with Provider objects, now do I need to release all Provider objects before releasing arrProvider or I can just release it ?

Quote:
Originally Posted by smasher View Post
Also, if you click the gray arrow next to the address of your leaked NSPlaceholderString you can see that "history" of that memory address. Start at the bottom (most recent) and look up until you see malloc. That will be the history of every time that object was malloc'd, retained, and released. Somewhere in there is a retain without a release.
YES its shows malloc, release, malloc and then autorelease. autorelease is not cleaning anything so its becomes a leak.

Quote:
Originally Posted by smasher View Post
PS - I am able to create a similar leak in my own code if I modify ProviderID, LastName, or FirstName directly, without using "provider.blah = blah" or "self.blah = blah". Are you, in any location, changing the variable without using the property?
NO - the object once instantiated never modifies.


I also need to know the View that we push in the navigation controller - do we need to release it too?
I am autoreleasing it like this
Code:
Providers *ProviderView = [[[Providers alloc] CustomInitWithNibName:@"Providers" bundle:nil bIsProvider:YES] autorelease];

    [self.navigationController pushViewController:ProviderView animated:YES];

Thanks for all your help!!

Mubashir
_mubashir is offline   Reply With Quote
Old 07-03-2009, 02:05 PM   #13 (permalink)
Senior Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
Default

Quote:
Originally Posted by _mubashir View Post
I have put NSLog in dealloc and it gets called fine. Yes I am releasing arrProvider (NSMutableArray) in the appdelegate's dealloc. I am getting leak on Provider object as well so I assume its leaking. One thing I need to know is I have arrProvider filled with Provider objects, now do I need to release all Provider objects before releasing arrProvider or I can just release it ?
When the array gets deallocated, every object in the array gets a release message. This means that if you followed the rules so that (1) the array has a retainCount of one and (2) every object in the array has a retaincount of one, calling [array release] will deallocate both the array and every object inside. You should not need to remove them from the array or call release on them before releasing the array.

If you're getting a leak on a Provider object, hunt that down first - if you leak a Provider, every object in that provider may get leaked even if you followed the rules inside the Provider class.

Quote:
YES its shows malloc, release, malloc and then autorelease. autorelease is not cleaning anything so its becomes a leak.
Hunt down the Provider leak first. "malloc, release, malloc, autorelease" is the history of two different objects. The first object's history was "malloc, release" - it was released properly and destroyed. Then the address was reused for a second object, which as you said is getting leaked. I would expect "autorelease" to be followed by "release" when the autorelease pool clears; not sure why it isn't.

You will be an expert in the leaks tool by the time you are done.

Quote:
I also need to know the View that we push in the navigation controller - do we need to release it too?
I am autoreleasing it like this
Code:
Providers *ProviderView = [[[Providers alloc] CustomInitWithNibName:@"Providers" bundle:nil bIsProvider:YES] autorelease];

    [self.navigationController pushViewController:ProviderView animated:YES];
Not sure, someone else will have to answer - I haven't done navigationControllers for a while.
__________________
smasher is offline   Reply With Quote
Old 07-03-2009, 02:35 PM   #14 (permalink)
Registered Member
 
Join Date: Jun 2009
Posts: 43
Default

Thanks you kind sir - Its fixed

[arrProvider release] did the trick. I was just doing arrProvider = nil
So that was leaking the retained Provider objects.

Thank you so much for your time and help - Keep up the good work


Mubashir
_mubashir is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Enter the iPhone App Challenge!  Win $500!
» Advertisements
» Stats
Members: 24,113
Threads: 38,883
Posts: 170,571
Top Poster: smasher (2,563)
Welcome to our newest member, taptika
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 09:38 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.2.0