Reputation: 14834
As a new comer to Objective-c and its memory management technique, comparing two pieces below. (the original code was exacted from apple.com autorelease pools)
Questions:
1. Do the two pieces achieve the same result?
2. Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
3. Does the 2nd code below violate anything as far as best practices? Performance?
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
for (NSString *fileName in args) {
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
NSString *fileContents = [[[NSString alloc] initWithContentsOfFile:fileName
encoding:NSUTF8StringEncoding error:&error] autorelease];
/* Process the string, creating and autoreleasing more objects. */
[loopPool drain];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
NSString *fileContents = [[NSString alloc] autorelease];
for (NSString *fileName in args)
{
// NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSError *error = nil;
fileContents = [fileContents initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error];
/* Process the string, creating and autoreleasing more objects. */
//[loopPool drain];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
Upvotes: 2
Views: 380
Reputation: 104698
- Do the two pieces achieve the same result?
No. It's bound to blow up and/or leak when fileContents = [fileContents ...
is called the second time. Implementations assume their instance's memory is zeroed because that is guaranteed by the runtime.
Even if one initializer is proven to work without issue or leaks, many of them will not.
Don't try to 'renew' your objects like this - just please do it the normal way =)
The sequence (in a non-gc environment) should be: 1) alloc
2) init...
(using designated initializer) 3) dealloc
.
Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
No. In addition to what is outlined in #1, you should not assume the address returned from alloc
will be the same returned from the initializer. The initializer may choose to destroy the result of alloc
and create or return another allocation. In this case, you will introduce a reference count imbalance (effect: leak and/or zombie).
Does the 2nd code below violate anything as far as best practices?
NSString *fileContents = [[NSString alloc] autorelease];
is weird, very unconventional. The first time I read it, I missed the error because it is so conventional for init...]
to be placed between alloc
and autorelease
.
Does the 2nd code below violate anything as far as Performance?
Performance may suffer by removing the autorelease pool from the inner loop. When large allocations and/or high iterations occur, it's best to create small localized pools, like the original.
Upvotes: 5
Reputation: 29764
To answer your questions:
1) Do the two pieces achieve the same result?
No, they don't, mainly because the second example is incorrect, on two accounts.
NSString *fileContents = [[NSString alloc] autorelease]
makes very little sense. This line essentially allocates room for a string, and without even initializing it (and increasing its initial retain count to 1), telling it to put itself onto an autorelease pool. This is a big no-no. fileContents = [fileContents initWithContentsOfFile:fileName encoding:NSUTF8StringEncoding error:&error]
makes just as little sense. You're initializing a new object using old memory that has not been released or reset in any way, which is just undefined behavior. As Sherm Pendley mentioned, you cannot allocate space once and simply reuse that memory without concern, and since you have no idea how NSString
is defined internally, this can either simply leak memory or very simply blow up in your face. Another big no-no.The rest of the code appears to be fine (it does depend on what you're doing in the 'process' step). As others have pointed out, +alloc
and -init
are almost always paired with each other, but not just because of convention, but because that this pairing is simply the right thing to do. You must +alloc
memory before you can begin to use it, and you must -init
to get that memory zeroed and in the right condition to run properly. Any other combination might not be fit for use.
2) Do the two pieces achieve the same memory management result? ( as far memory cleaning up, leaking, etc.)
No, they definitely do not. The second one will leak large amounts of memory, and very well might not even run. The first once is definitely okay, but might not run efficiently due to the use of inner autorelease pools.
3) Does the 2nd code below violate anything as far as best practices? Performance?
Yes, it does, and in fact, even the first one might not run efficiently. Creating an inner autorelease pool might not be in your best interest, and might even hinder your program. The venerable Mike Ash did some testing with autorelease pools, and the results are a little surprising. It turns out that differently-sized autorelease pools will work better on different computers (back then, on his old computer, 100 objects was the most efficent per pool; for me, 10000 objects works a little bit better, and even then only marginally better than 1000 objects)
Upvotes: 1