hol
hol

Reputation: 8423

Objective-C Memory Leaking Understanding Question

I have a program that reads a huge text file (line by line) and does some string operations with each line before writing the line into a database.

The program needed more and more memory so I figured that I might need to release the strings that I use. But it did not help. So I have put together the following code to test out what actually happens. With some trial and error I found out that when I do the drain on the autorelease pool it works.

I would like to know what I do. So I ask:

Here is my test program

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

int cnt = 0;

while (cnt < 1000000000) {
    NSMutableString *teststr = [[NSMutableString alloc] init];

    teststr = [NSString stringWithString:@"Dummy string just for the demo"];

    cnt++;
    if (cnt % 1000000 == 0) {
        printf("cnt=%i\n",cnt);
    }

    [teststr release];


//      [pool drain];                      // It works when I do this 
//      [[NSAutoreleasePool alloc] init];  // and this

}

[pool drain];
return 0;
}

EDIT: Based on the answers so far I have looked on my original program and changed the test program:

//teststr = [NSString stringWithString:@"Dummy string just for the demo"];

[teststr appendString:@"Dummy string just for the demo"];

Does this also create a new string? Because still I have the memory problem. My routine works in way that I append the string with something but maybe start with an empty string at the beginning.

Upvotes: 0

Views: 139

Answers (3)

hol
hol

Reputation: 8423

The above example was not really having so much the memory problem. My more complicated program "leaked" memory and this was because of the following statement which consumed up memory without a drain.

NSString *conv = [dict objectForKey:astring]];

It is not really a leak but several statements of that kind and an iteration of several hundred thousand caused a big issue. The solution was to drain the autorelease pool. But draining the autorelease pool had the disadvantage that the dictionary object (dict) which I use was drained, too.

So this handled it. I opened a second pool:

NSAutoreleasePool * pool2 = [[NSAutoreleasePool alloc] init];

NSString *conv = [dict objectForKey:astring]];

/* do something */

[pool2 drain];

Upvotes: 0

kennytm
kennytm

Reputation: 523264

NSMutableString *teststr = [[NSMutableString alloc] init];

This allocates a mutable string....

teststr = [NSString stringWithString:@"Dummy string just for the demo"];

and then this overrides the teststr variable with an autoreleased string. The allocated mutable string is now inaccessible, but still having a retain count of +1, so it will be leaked.

[teststr release];

This will only release the autoreleased string, causing double-free error in the future.


If you want a manually-managed mutable string, you should use

NSMutableString* teststr = [[NSMutableString alloc] initWithString:@"Dummy string just for the demo"];
...
[teststr release];

and don't assign to teststr directly, before it is released or the ownership is transferred.

Upvotes: 2

Hemant
Hemant

Reputation: 19826

You are making one very basic mistake.

  1. You have to release an object when you call alloc/init on it.
  2. An object is auto-released if you get an object using other means (convient constructors, returned objects of methods etc).

The method stringWithString returns a new autoreleased string so there is no point for to alloc/init it. Also since it is auto-released object, draining the auto-released pool helps.

So instead of:

NSMutableString *teststr = [[NSMutableString alloc] init];
teststr = [NSString stringWithString:@"Dummy string just for the demo"];

Try this:

NSMutableString *teststr = [NSString stringWithString:@"Dummy string just for the demo"];

Upvotes: 1

Related Questions