Welcome to MacForumz.com!
FAQFAQ      ProfileProfile    Private MessagesPrivate Messages   Log inLog in

Basic memory management question

 
   Macintosh computer (Home) -> Programmer Help RSS
Next:  Application Quits when Printing  
Author Message
sebastien.wailliez

External


Since: Jan 14, 2008
Posts: 3



(Msg. 1) Posted: Mon Jan 14, 2008 12:50 pm
Post subject: Basic memory management question
Archived from groups: comp>sys>mac>programmer>help (more info?)

Hello,

I have a big memory leak in a method which simply reads from a text
file and adds each line to an NSMutableArray as an NSString, and then
return the array to the caller.

I'm positive that the memory used by the array of strings is not freed
unless Activity Monitor and ObjectAlloc both lie. ObjectAlloc does not
show any decrease in the number of allocated (and living!) CFStrings,
whatever I try to get the memory freed.

I'm new to Obj-C and from what I read in the Apple documentation,
arrays retain added objects and release removed objects. So I would
expect all lines to be released when the array gets out of scope.
Which it should do in the calling function, as I used autorelease on
the array. I tried without autorelease and an explicit release message
in the calling function, I tried removeAllObjects... Nothing works.
Any clue?

Cheers!


- (NSMutableArray*) readFileLines :(NSString*)path
{
NSError* err;
NSMutableArray* arr = [[NSMutableArray alloc] init];
NSString* contents = [NSString stringWithContentsOfFile :path
encoding:NSUTF8StringEncoding error:&err ]; // error unhandled

if( contents )
{
NSString* line;
NSScanner* scanner = [NSScanner scannerWithString :contents];
NSCharacterSet* lb = [NSCharacterSet
characterSetWithCharactersInString :@"\x0a\x0d"];

while( [scanner scanUpToCharactersFromSet :lb intoString:&line] )
[arr addObject :line];
}

return [arr autorelease];
}

 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
Fritz Anderson

External


Since: Dec 01, 2007
Posts: 3



(Msg. 2) Posted: Tue Jan 15, 2008 7:26 am
Post subject: Re: Basic memory management question [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

On Jan 14, 2:50 pm, sebastien.waill....DeleteThis@gmail.com wrote:
> I have a big memory leak in a method which simply reads from a text
> file and adds each line to an NSMutableArray as an NSString, and then
> return the array to the caller.
>
> I'm positive that the memory used by the array of strings is not freed
> unless Activity Monitor and ObjectAlloc both lie. ObjectAlloc does not
> show any decrease in the number of allocated (and living!) CFStrings,
> whatever I try to get the memory freed.
>
> I'm new to Obj-C and from what I read in the Apple documentation,
> arrays retain added objects and release removed objects. So I would
> expect all lines to be released when the array gets out of scope.
> Which it should do in the calling function, as I used autorelease on
> the array. I tried without autorelease and an explicit release message
> in the calling function, I tried removeAllObjects... Nothing works.
> Any clue?
>
> Cheers!
>
> - (NSMutableArray*) readFileLines :(NSString*)path
> {
> NSError* err;
> NSMutableArray* arr = [[NSMutableArray alloc] init];
> NSString* contents = [NSString stringWithContentsOfFile :path
> encoding:NSUTF8StringEncoding error:&err ]; // error unhandled
>
> if( contents )
> {
> NSString* line;
> NSScanner* scanner = [NSScanner scannerWithString :contents];
> NSCharacterSet* lb = [NSCharacterSet
> characterSetWithCharactersInString :@"\x0a\x0d"];
>
> while( [scanner scanUpToCharactersFromSet :lb intoString:&line] )
> [arr addObject :line];
> }
>
> return [arr autorelease];
>
> }

Okay, so I rigged up a testbed application that got a path from
NSOpenPanel, passed it to your method, and retained the result. It
could also release the string array on command. It used bindings to
text fields to display the path and the count of the line array. I ran
it through a cycle of open, then release. I did this under
Instruments, with the ObjectAlloc and Leaks instruments running.

The application allocated 32348 CFStrings throughout its history. The
peak in allocations came when the open panel opened (adding ~19000
strings). Between loading and purging the line array, about 300
strings were allocated and released, which isn't crazy for a 60-line
file. None of those strings survived after the release.

The large number of strings allocated for the open panel stuck around.
This isn't crazy either; the shared NSOpenPanel sticks around after
its first use.

The Leaks instrument found one 16-byte block leaked by the time the
application quit. One. And none during the time the line array lived.

Your problem (if any) isn't with the method you posted (unless my
technique is much amiss). How did you determine that your method is
the source of a leak?

Remember that Foundation and AppKit allocate many, many strings for
their own purposes. This would also explain the rise in memory showin
in Activity Monitor. Also, Activity Monitor memory usage statistics
tend to rise monotonically. Malloc memory is allocated by partitioning
out large chunks of memory obtained from the OS. Those large chunks do
not get recycled; memory released within those chunks does get
recycled.

> So I would
> expect all lines to be released when the array gets out of scope.
> Which it should do in the calling function, as I used autorelease on
> the array.

Not quite. Unless you set up an NSAutoreleasePool of your own, and
release it yourself, the current pool won't be released until the next
pass through the event loop.


-- F

 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
Gregory Weston1

External


Since: Oct 03, 2004
Posts: 1917



(Msg. 3) Posted: Tue Jan 15, 2008 9:28 am
Post subject: Re: Basic memory management question [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

In article
<795a7c3f-fcbb-4704-b9fe-a076a2ce8fc0 RemoveThis @k39g2000hsf.googlegroups.com>,
sebastien.wailliez RemoveThis @gmail.com wrote:

> Hello,
>
> I have a big memory leak in a method which simply reads from a text
> file and adds each line to an NSMutableArray as an NSString, and then
> return the array to the caller.
>
> I'm positive that the memory used by the array of strings is not freed
> unless Activity Monitor and ObjectAlloc both lie. ObjectAlloc does not
> show any decrease in the number of allocated (and living!) CFStrings,
> whatever I try to get the memory freed.
>
> I'm new to Obj-C and from what I read in the Apple documentation,
> arrays retain added objects and release removed objects. So I would
> expect all lines to be released when the array gets out of scope.
> Which it should do in the calling function, as I used autorelease on
> the array.

You've misunderstood a few things:

An object is only deallocated when its retain count goes down to zero.
Sending a release message to an object decrements its retain count, but
you don't know (and shouldn't care) what the retain count actually *is*
at that point. All your job is is to make sure that every object you
allocate, copy or retain eventually gets a release message.

When you send autorelease to an object, the object gets registered to
receive a release message at some point in the future. There's no
promise made regarding *when* but it doesn't happen when the variable
goes out of scope and you really wouldn't want it to else you'd never be
able to reliably return an object as a function result. As an
implementation detail in extant releases of the framework, it will
happen at the end of the current pass through the event loop unless
you've introduced your own autorelease pool in the course of your
processing.

> I tried without autorelease and an explicit release message
> in the calling function, I tried removeAllObjects... Nothing works.
> Any clue?

Most likely the strings are still being retained by something at the
point where you're taking your measurements.

The short answer is: There's no leak in the code you posted as far as I
can see.
 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
sebastien.wailliez

External


Since: Jan 14, 2008
Posts: 3



(Msg. 4) Posted: Wed Jan 16, 2008 1:04 am
Post subject: Re: Basic memory management question [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Thanks for all the comments (and experiments)!

> Unless you set up an NSAutoreleasePool of your own, and
> release it yourself, the current pool won't be released until the next
> pass through the event loop.

This is exactly what I did by having the heavy-duty text processing
execute in a detached thread with its own autorelease pool.
Structurally, the program does the following:


- (void) anotherMethodRunningInTheMainThread
{
[NSThread detachNewThreadSelector :@selector(myThread)
toTarget:self withObject:nil];
}

- void myThread :(id)param
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSMutableArray* lines = [readFileLines:thePath]; // path to a big
text file

for( unsigned i = 0, nlines = [lines count]; i < nlines; i++ )
{
NSString* line = [lines objectAtIndex :i]; // is this only
released at thread termination?
// Do the CPU-intensive stuff // should I
look for an involuntary retain message in here?
}

[pool release];
}
 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
sebastien.wailliez

External


Since: Jan 14, 2008
Posts: 3



(Msg. 5) Posted: Wed Jan 16, 2008 11:21 am
Post subject: Re: Basic memory management question [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

Well, it is now clear that the array of string was not the problem.
The leak does come from the processing loop inside my thread and I
have identified two culprits:

- NSString's cStringUsingEncoding. Its return value (a const char*) is
not supposed to be freed by the programmer but I can see it is not
deallocated by the Cocoa runtime either.

- the following code inside my processing loop leaks about 40 bytes
per iteration:

// the user object has a (NSValue*) getRecord { return [NSValue
valueWithPointer :record]; } method.
NSValue* ptrVal = [user
performSelector:aSelectorThatPointsToGetRecord];
char* record = (char*)[ptrVal pointerValue]; // the problem is really
the line above

This is still quite mysterious to me...
 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
Reinder Verlinde

External


Since: Feb 18, 2004
Posts: 128



(Msg. 6) Posted: Wed Jan 16, 2008 3:33 pm
Post subject: Re: Basic memory management question [Login to view extended thread Info.]
Archived from groups: per prev. post (more info?)

In article
<fac6f5fc-bde7-4d7c-981f-7a49c81ff26f.TakeThisOut@i7g2000prf.googlegroups.com>,
sebastien.wailliez.TakeThisOut@gmail.com wrote:

> Well, it is now clear that the array of string was not the problem.
> The leak does come from the processing loop inside my thread and I
> have identified two culprits:
>
> - NSString's cStringUsingEncoding. Its return value (a const char*) is
> not supposed to be freed by the programmer but I can see it is not
> deallocated by the Cocoa runtime either.

<http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Clas
ses/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString
/cStringUsingEncoding:> says:

"The returned C string is guaranteed to be valid only until either
the receiver is freed, or until the current autorelease pool is
emptied, whichever occurs first. You should copy the C string or use
getCString:maxLength:encoding: if it needs to store the C string
beyond this time."

Reinder
 >> Stay informed about: Basic memory management question 
Back to top
Login to vote
Display posts from previous:   
   Macintosh computer (Home) -> Programmer Help All times are: Pacific Time (US & Canada) (change)
Page 1 of 1

 
You can post new topics in this forum
You can reply to topics in this forum
You can edit your posts in this forum
You can delete your posts in this forum
You can vote in polls in this forum



[ Contact us | Terms of Service/Privacy Policy ]