Assign nil to NSString within Autorelease pool - objective-c

I'm making a great deal of NSString manipulations within an autorelease pool. Problem is my program will sometimes crash before the pool drains. I'm wondering if there is a way to circumvent this problem by assigning nil to NSString. The assignment to userLetters happens a lot. See code below
Before
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
usersLetters = [usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"];
[pool drain];
After
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *temp = [usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"]; //remove that found character so it can't be reused again
usersLetters = nil;
usersLetters = temp;
temp = nil;
[pool drain];

I doubt what assigning to nil will help in what you want to achieve.
(I assume you mean that your program crashes because the memory is exhausted, otherwise, it is much more likely that you released to often somewhere, you should also run the Status Analyzer over your code.)
What you can do is to send a retain message to all objects that you still need (in your case usersLetters) and drain the pool afterwards. The objects that you still need should then have a retain count of 1, all other autoreleased objects should have been deallocated.
In your case, this would be
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
usersLetters = [[usersLetters stringByReplacingCharactersInRange:NSMakeRange(indexUser, 1) withString:#"*"] retain]; //sending retain to an object increases its retain count by 1 and returns the object itself
// some more stuff that needs memory
[pool drain];
// ...
[usersLetters release];
[pool release];

You don't mention if your project targets iOS or Mac OS X. If the latter, the best way to resolve this issue may be to simply use garbage collection.
If GC is not an option (which it is not on iOS), the idiomatic way to deal with this is to wrap a nested autorelease pool around your inner, fast-allocating operations. In this case you must retain any objects which need to outlive the nested pool, as mrueg has explained.

Related

Why is memory sometimes deallocated immediately and other times only when autorelease pool is drained?

I made simple experiment and found some strange behavior. Here some code - part of long method with ARC enabled:
MKObject *obj = [[MKObject alloc]init];
NSMutableArray *temp = [[NSMutableArray alloc]init];
[temp addObject:obj];
obj = nil;
temp = nil;
//here deallocating is called on obj (MKObject)
//other stuff
but if I change NSMutableArray to NSArray and literal initialisation
NSArray *temp = #[obj];
deallocating executed before autoreleasepool closed, not after setting nil to all references. Did I missed something ?
A few observations:
In your first example, neither the MKObject nor the NSMutableArray is an autorelease object, so these objects will be deallocated immediately, not waiting for the autorelease pool to drain:
MKObject *obj = [[MKObject alloc] init];
NSMutableArray *temp = [[NSMutableArray alloc] init];
[temp addObject:obj];
obj = nil;
temp = nil;
In your second example, the NSArray is an autorelease object, so the NSArray (and therefore, the MKObject) will not be deallocated until the autorelease pool is drained.
MKObject *obj = [[MKObject alloc] init];
NSArray *temp = #[obj];
obj = nil;
temp = nil;
To understand why the array literal, #[], creates an autorelease object, one should note that it expands to +[NSArray arrayWithObjects:count:]. Autorelease objects are created whenever you instantiate an object with any method other than using alloc followed by an init (whether init, or one of the permutations, such as initWithObjects:).
As you observed, when an app creates autorelease object, the object will not be immediately be deallocated, but it will when the autorelease pool drains. Since we generally yield back to the runloop quickly (at which point the pool will be drained), the choice of autorelease objects or non-autorelease objects has little practical impact in simple cases. But if the app, for example, has a for loop in which it creates many autorelease objects without yielding back to the runloop, it could be problematic (especially if MKObject was large or you were doing this many times). For example:
for (NSInteger i = 0; i < 100; i++) {
MKObject *obj = [[MKObject alloc] init];
NSArray *temp = #[obj];
// Note, because they are local variables which are falling out of scope, I don't have to manually `nil` them.
}
Because we are instantiating autorelease NSArray objects in this example, the above would keep all 100 arrays and objects in memory until you yielded back to the runloop and the autorelease pool had a chance to drain. This means that the app's "high water mark" (the maximum amount memory it uses at any given time), would be higher than it might need to be. You could remedy this by either:
use a non-autorelease object (such as by using alloc/init) instead of using the array literal:
for (NSInteger i = 0; i < 100; i++) {
MKObject *obj = [[MKObject alloc] init];
NSArray *temp = [[NSArray alloc] initWithObjects:obj, nil];
}
or
by introducing your own, explicitly declared #autoreleasepool:
for (NSInteger i = 0; i < 100; i++) {
#autoreleasepool {
MKObject *obj = [[MKObject alloc] init];
NSArray *temp = #[obj];
}
}
In this final example, the autorelease pool will be drained for each iteration of the for loop, resolving any challenges with autorelease objects that would otherwise have their deallocation deferred until the end of the loop.
One final caveat: In general, methods that begin with alloc and init (or a variation of the init method), will not generate autorelease objects, whereas all other methods, such as arrayWithObjects:count: will generate autorelease objects. One notable exception is the NSString class, which due to internal memory optimizations, does not conform to this rule. So, if you have any doubt, you can employ your own manual #autoreleasepool if you are repeatedly instantiating and releasing objects, and you are unsure as to whether the objects are autorelease objects or not. And, as always, profiling your app with the Allocations tool in Instruments is a good way of observing the app's high water mark. For an illustration of how these various techniques can impact the memory usage of your app, see https://stackoverflow.com/a/19842107/1271826.
The array was being retained by the autorelease pool. As described in Clang's Objective-C Literals documentation, the array literal syntax expands to a call to +[NSArray arrayWithObjects:count:], which creates an autoreleased array.
A couple of things I see, though I'm not entirely clear on the question so I can't say which applies:
Adding an object to an NSArray or NSMutableArray increments the object's retain count.
In the first instance, you manually instantiate obj, which gives it retain count 1.
Adding it to the NSMutableArray makes its retain count 2.
In this case, obj = nil decrements retain to 1;
temp = nil tells the array to handle releasing its contents. Those w/retain count 0 get dealloc'd immediately.
In the 2nd instance with #[] literal creation, the literal syntax under the hood creates an autoreleased object using the method arrayWithObjects: count:. When this is no longer needed it goes to the autorelease pool for eventual deallocation.
It isn't an issue of the objects IN the array but the way the arrays themselves were created.
Edited my original response to address comments below - I was confusing the issue.

Is this the right way to use NSAutoreleasePool?

I'm new to Objective-C and I'm not sure if I'm using NSAutoreleasePool the right way.
If I want to use autorelease only one time I use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool release]; //newText will be released
If I want to use autorelease several times I use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool drain]; //newText will be released
newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool drain]; //newText will be released
newText = [NSString stringWithFormat:#"%d", prograssAsInt];
sliderLabel.text = newText;
[pool release]; //newText will be released
Is this OK? Are there any memory leaks?
(2) is not OK. -drain and -release are equivalent (in a ref-counting environment), and aftering -draining the autorelease pool is deallocated. So you will double-release the autorelease pool object and crash the program.
Even before ARC, unless you are working in a very tight memory budget, it's atypical to create an NSAutoreleasePool besides the boilerplate main(). The objects -autoreleased into the pool will be released after every tick of NSRunLoop anyway. There will be no memory leak if you strictly follow the ownership transfer rules (see Understanding reference counting with Cocoa and Objective-C).
And with ARC turned on you don't even need to care about this — the compiler will insert the -retain and -release at the right place for you.
Also, if sliderLabel.text is marked as #property(retain) (or (strong)), then releasing the autorelease pool in (1) will not release the newText because that object has a new owner now.
I would say the calls to [pool drain] are unnecessary. I've never seen them used in practice. I suppose if you are allocating huge amounts of memory inside the autorelease pool, it might be necessary. But in the typical case, I would think not.
You will want to start using the following construct, by the way, for autorelease pools:
#autoreleasepool {
... your code ...
}
This is, apparently, much more efficient than the "old" way (the way you are doing it). Functionally, it's the same, but internally it performs much better. There was something about this in recent Xcode/iOS release notes.
Sorry to say this, but RTFM. After -drain is called, the pool deallocates itself, so that it is invalid.
And, currently, in objective-c with Apple's LLVM compiler, there is a language addition called #autoreleasepool that works with both ARC and non-ARC code, that you can leverage as such:
#autoreleasepool {
// code that will automatically have any -autoreleased variables cleaned up.
}
Normally, if you're on the main thread and you're not using a huge loop of resource intensive code, you don't ever need to create your own autorelease pools. Just use the default one that's created for you.
You only need to make your own if you're multithreading or if you're doing a memory intensive long-running loop (which you probably shouldn't do on the main thread anyway).

objective c Thread in Thread variables life time

I have an NSOperation where inside its -main method I use [NSThread detachNewThreadSelector:#selector(aMethod:) toTarget:self withObject:anArgument];
aObject (instance variable of my NSOperation subclass) is a weak reference to an object of an autoreleased array returned inside the -main method...
-(void)main {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *clients = [group produceClients]; // clients array is an autorelease instance
self->aObject = [clients objectAtIndex:3]; // a weak reference, Lets say at index three!
[NSThread detachNewThreadSelector:#selector(aMethod:)
toTarget:self
withObject:#"I use this for another thing"];
// Do other things here that may take some time
[pool release];
}
-(void)aMethod:(NSString*)aStr {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// aStr object is reserved for another functionality
// I know that I could pass a NSDictionary with a number of entries, which would be
// retained by `detachNewThreadSelector` but then ...
// I wouldn't have to ask this question ! :)
// Do several things with aObject, which is a weak reference as described above.
NSLog(#"%#", [self->aObject.id]);
// Is it safe ?
[pool release];
}
I know that NSThread's detachNewThreadSelector method retains self and withObject:anArgument, but what happens to aObject ?? Is it sure that will exist during the execution of the detached thread (aMethod:) ? Self is retained by detachNewThreadSelector, does this mean that the pool of the -main thread will be delayed released since it is retained and thus the clients will exist and thus the aObject will exist ?
Or the -main (NSOperation) thread will finish execution and released before -aMethod (NSThread) finishes so it's unsafe to use aObject there ?
The real question is: When calling [NSThread detachNewThreadSelector:#selector(aMethod:) ...toTarget:self ...] from inside a thread, does the last thread being retained in a way that its autoreleased instances (clients array) are safe to be used in aMethod (self->aObject) (lets say via weak references) ?
Your approach seems highly unstable, but I'm not an expert on multithreading so I could be wrong. Your clients array is in the main autorelease pool, which you cannot be assured will wait till your aMethod thread is completed to drain. What about this:
-(void)main {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(aMethod:)
toTarget:self
withObject:#"I use this for another thing"];
[pool release];
}
-(void)aMethod:(NSString*)aStr {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *clients = [group produceClients]; // clients array is an autorelease instance
self->aObject = [clients objectAtIndex:3]; // a weak reference, Lets say at index three!
[pool release];
}
With this approach, your clients array is in the thread's autorelease pool.

Objective-c memory management

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);
}
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.
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.
Firstly, 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.
And second, 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)

When to release. Instruments says I have a leak

Sometimes I wonder where I would be able to get great information other than from the stack overflow community. I suppose the Objective-C memory management handbook wouldn't be bad, but I feel like you guys can tell me why as opposed to just what to do.
I have the following code:
NSString* rawTickerData = [[NSString alloc] initWithData: op.requestData encoding:NSUTF8StringEncoding];
NSArray* lines = [rawTickerData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for(NSString* line in lines)
{
NSArray* fields = [line componentsSeparatedByString:#","];
if([fields count] > 1)
{
[self.tickerData addObject:fields];
}
}
[rawTickerData release]
Instruments tells me that fields is leaking, but trying to release it after the if statement or doing an autorelease gives an EXC_BAD_ACCESS.
The same thing happens for lines. Releasing it anywhere or trying to do autorelease gives EXC_BAD_ACCESS or "trying to double free" (for autorelease).
Yet, instruments is still saying that these are leaking. Am I missing something?
Unless I'm missing something, the code you've posted is correct. fields is an autoreleased object that gets retained when added to self.tickerData. lines is also autoreleased, so it isn't leaking (at least not in the code shown).
If you're leaking anywhere, it's because you're not properly cleaning up self.tickerData. If you comment out the [self.tickerData addObject:fields]; line, are you still getting leaks reported? If not, make sure you're calling [tickerData release] (or something similar, like self.tickerData = nil) somewhere, probably in your dealloc implementation.
In these cases the best practice is to release your object's at the end of each loop, if you retained them. In this case your fields variable gets an autorelease object, the best option is to use an NSAutoReleasePool to release your objects at the end of the loop.
NSAutoreleasePool *pool;
pool = [[NSAutoreleasePool alloc] init];
NSString* rawTickerData = [[NSString alloc] initWithData: op.requestData encoding:NSUTF8StringEncoding];
NSArray* lines = [rawTickerData componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
for(NSString* line in lines)
{
NSArray* fields = [line componentsSeparatedByString:#","];
if([fields count] > 1)
{
[self.tickerData addObject:fields];
}
[pool drain];
}
[rawTickerData release];
This will flushes all the autoreleased objects if they are don't needed. If you dont use autorelease pool, your objects are living until your method terminates.
If this doesn't resolve your leak problem i suggest to initialize your array like this:
NSArray *lines = [[NSArray alloc]initWithArray:[line componentsSeparatedByString:#","]];
//and release at the end of the loop
[lines release];