 |
 |
|
 |
07-02-2009, 02:03 PM
|
#1 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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
|
|
|
07-02-2009, 02:24 PM
|
#2 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
|
Quote:
Originally Posted by _mubashir
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
|
|
|
07-02-2009, 02:41 PM
|
#3 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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
|
|
|
07-02-2009, 03:35 PM
|
#4 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 338
|
It's probably something in that Provider class, are you creating something there that you aren't releasing?
|
|
|
07-02-2009, 03:49 PM
|
#5 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
|
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.
__________________
|
|
|
07-03-2009, 01:34 AM
|
#6 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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
|
|
|
07-03-2009, 02:45 AM
|
#7 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
|
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?
__________________
|
|
|
07-03-2009, 03:32 AM
|
#8 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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
|
|
|
07-03-2009, 03:38 AM
|
#9 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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];
}
|
|
|
07-03-2009, 11:14 AM
|
#10 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
|
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
|
|
|
07-03-2009, 11:30 AM
|
#11 (permalink)
|
|
Registered Member
Join Date: Apr 2009
Posts: 11
|
Quote:
Originally Posted by _mubashir
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
|
|
|
07-03-2009, 01:13 PM
|
#12 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
Quote:
Originally Posted by smasher
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
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
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
|
|
|
07-03-2009, 02:05 PM
|
#13 (permalink)
|
|
Senior Member
iPhone Dev SDK Supporter
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 2,563
|
Quote:
Originally Posted by _mubashir
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.
__________________
|
|
|
07-03-2009, 02:35 PM
|
#14 (permalink)
|
|
Registered Member
Join Date: Jun 2009
Posts: 43
|
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
|
|
|
 |
| Thread Tools |
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
» Advertisements |
» Online Users: 573 |
| 52 members and 521 guests |
| 6ix, alexz1, amit.wizkid, Argus, asimrs, bebus77, Blitfast, BrianSlick, CapsicumDreams, cdstamper, coconnor, DonomaGames, dre, d_amal, eric@cybercat.ca, fdifenza, gedalia, Georg, gladiator430, Guit, HemiMG, ieasyproductions, javaconvert, jbullfrog, jimkberry, JonnyBGoode, lepetitapps, luigi1977, magalhaes, mebarron, MikaelBartlett, naomipunkclan, paschi, Pedro Valentini, Picoman, rocketman240, sayhong, seezee, taptika, Thaurin, tmccphoto, tychop, ugur, warcrow, warmi, yannickd60, yojung, yujean, ziocleto |
| Most users ever online was 779, 05-11-2009 at 09:55 AM. |
» Stats |
Members: 24,113
Threads: 38,883
Posts: 170,571
Top Poster: smasher (2,563)
|
| Welcome to our newest member, taptika |
|