Why does this program take up so much memory?
I am learning Objective-C. I am trying to release all of the memory that I use. So, I wrote a program to test if I am doing it right:
#import <Foundation/Foundation.h>
#define DEFAULT_NAME @"Unknown"
@interface Person : NSObject
{
NSString *name;
}
@property (copy) NSString * name;
@end
@implementation Person
@synthesize name;
- (void) dealloc {
[name release];
[super dealloc];
}
- (id) init {
if (self = [super init]) {
name = DEFAULT_NAME;
}
return self;
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleas开发者_如何学GoePool * pool = [[NSAutoreleasePool alloc] init];
Person *person = [[Person alloc] init];
NSString *str;
int i;
for (i = 0; i < 1e9; i++) {
str = [NSString stringWithCString: "Name" encoding: NSUTF8StringEncoding];
person.name = str;
[str release];
}
[person release];
[pool drain];
return 0;
}
I am using a mac with snow leopard. To test how much memory this is using, I open Activity Monitor at the same time that it is running. After a couple of seconds, it is using gigabytes of memory. What can I do to make it not use so much?
Firstly, your loop is incorrect. +stringWithCString:…
is not an +alloc
/+new…
/-copy
method, so you should not -release
it.
Either one of these are correct:
Don't
-release
:str = [NSString stringWithCString: "Name" encoding: NSUTF8StringEncoding]; person.name = str;
Use
-init
:str = [[NSString alloc] initWithCString: "Name" encoding: NSUTF8StringEncoding]; person.name = str; [str release];
Similarly, in -[Person init]
:
- (id) init {
if ((self = [super init])) {
name = [DEFAULT_NAME copy]; // <----
}
return self;
}
Now, if you use variant #1, the memory should rise up to gigabytes as you have seen before, while variant #2 should be a rather constant, small value.
The difference is because
str = [NSString stringWithCString: "Name" encoding: NSUTF8StringEncoding];
is equivalent to
str = [[[NSString alloc] initWithCString:......] autorelease];
An -autorelease
d object means "transfer the ownership to the nearest NSAutoreleasePool, and let it release it later".
How late? By default, it's when the current run loop ticked once. However, you did not have an explicit run loop here*, so the run loop did not run. The autorelease pool never have a chance to clear up these 109 allocated temporary strings.
However, for variant #2, the temporary strings are immediately released, so the temporaries won't fill up the memory. (We don't need to wait for the pool to flush — there's no pools involved.)
Note:
*: A run loop is a unique loop attached to each running thread. If you write a CLI utility, there's seldom need to have a run loop.
精彩评论