views:

745

answers:

3

I am using an XMLParser to parse some XML data, which uses an NSMutableString *resultString to store the tag characters. At every (- parser: didStarElement...) method I allocate and init the resultString-ivar.

-  (void)parser: (NSXMLParser *)parser didStartElement: (NSString *)elementName namespaceURI: (NSString *)namespaceURI qualifiedName: (NSString *)qName attributes: (NSDictionary *)attributeDict { 
// Alot of if-statements to sort subtags
// /.../
    resultString = [[NSMutableString alloc] init];
    recordResults = YES;
}

The string is appended in the parser:foundCharacters-method. I read somewhere that autoreleased objects, like the string inside appendString could cause the image of a memory leak. So i added a local autorelease pool to make sure it got drained right away (no change in behavior though):

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
if(recordResults) {
    [resultString appendString: string];
}
[pool drain];
}

In the parser:didEndElement... I finally release and nil out the resultsString:

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

   // Alot of if statements to handle differnt tags
   // each of which has the structure of the last else-statement
   // In other words, I am pretty sure I've covered every possible
   // case to prevent the resultString from
   // not getting released and niled out
    if(...) {
            ...
}
    else if(...) {
            ...
    }
else {
    if(resultString != nil) {
        [dataDict setObject: resultString forKey: elementName];
        [resultString release];
        resultString = nil;
    }
}

Instruments Leak-tool flags the parser:foundCharacter-method as a source for memory leakage, so I wonder if this is caused by appendString. Or if you can find something in this code that is way out wrong. This is a rather memory craving application, parsing quite a few and sometimes moderately big XML-files on an iPhone, so my question would be how to find a work around, if the NSMutableString appendString is not appropriate in this case...

Thanks in advance!

A: 

I don't think you can know if appendString is using autorelease or not because the method changes it's object rather than returning a new object. In other words, because it's changing itself you're not responsible for it's memory management. You also don't own string so you don't have to release or autorelease it.

Check this out: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH

That will probably clarify things, but the key thing with autorelease is that "new" objects returned by something other than alloc/init areautoreleased. In this case no new object is returned by appendString, and string could simply be retained, passed into the parser callback, then released by the caller later, so who knows if that's autoreleased.

The time when you have to autorelease something is when you have a function/method that uses alloc/new/copy, then returns the object with no way for the function itself to release it in the future.

Nimrod
I agree that I could just as well omit the autorelease pool. I got a hint about that here at stackoverflow, and though I couldn't see why it should help, I tried it. I tried to mention that in the first post, but obviously wasn't clear enough.
jollyCocoa
+2  A: 

If an end tag is missing, you will have a memory leak. It is better to have any allocations in parserDidStartDocument: and deallocations in parserDidEndDocument:, as these are guaranteed to be paired. And instead of allocating resultString in didStartElement, you just truncate it there.

ergosys
I'm not sure if parserDidEndDocument is called if there is a parsing error, but this should be easy to test.
ergosys
Good point! Should make some performance improvements to, right, since I don't have to alloc and init the NSMutableString for every tag? And by truncating you're suggesting just setting [resultString setString:@""]?
jollyCocoa
I tried this solution of yours. It seems to have solved the problem. Thanks alot!I am pretty fortunate to work with XML's that all come with closing tag. But if not I guess I could implement parser:parseErrorOccured or something to handle those...
jollyCocoa
Not solved unfortunately, but I think you put me on the right track. Will comment when I've solved this or need some more feedback. Still thanks...
jollyCocoa
The problem with your suggestion is that, by truncating resultString without repointing it, I also change the value in the Dictionary to which it is added. I don't seem to find any remedy to this other than releasing it and niling it out, as in my first codeexample...
jollyCocoa
Add a copy of resultString to the dictionary.
ergosys
Obvious... Of course that could solve the problem...
jollyCocoa
I don't really know what I was thinking... :)
jollyCocoa
A: 

The auto-release pool is doing nothing, since you are not auto-releasing any objects - you are allocing the mutable string in one location, releasing it in another. "appendString" does nothing at all to the retain count of a MutableString.

As for the leak, here is the deal - Leaks is telling you where memory leaking was allocated. So that means that everything is OK in the part that allocates the memory - what is not OK, is that somewhere else the memory that was retained in that method was supposed to be released and it was not.

So at some point later, it would seem you get out resultString from the dataDict you place it in, retain it and do not release it (it seems to me like you release it OK in parsing so that would not be the culprit). To verify this is so, change the insert of the string to be::

 [dataDict setObject:[[resultString copy] autorelease] forKey: elementName];

And leaks should tell you the leak is there. To help track down the leak, any time you extract a string from that dataDict, you can [copy] it and then you will get closer to the exact code that is leaking strings.

Basically Leaks is like the opening of a mystery book with someone dead. It's up to you to figure out who the killer is - or in the case of leaks, who was supposed to do the killing but didn't get around to it.

Kendall Helmstetter Gelner
Yes, you are right. However. It doesn't really harm either, and I still have the leak, so I am still confused.
jollyCocoa
I added a note on what leaks is really telling you to my response, sorry I didn't get into more detail on that the other evening but I was in too much a hurry at the time.
Kendall Helmstetter Gelner