Analyzer is complaining about a possible resource leak in multithreaded Cocoa app - objective-c

Ok, I am an experienced C++ developer. I am learning Objective-C on the fly while trying to build a fairly substantial Cocoa application. I have done some simpler apps with Cocoa while gearing up for this project and I think I have a good handle on most of the concepts.
The memory management paradigm is still a little vague to me however so I build with the memory analyzer to help me find issues right away, and to be honest it has been awesome and has done more to help me understand Objective-C memory management that any of the documentation.
So here is my question.
I have two threads that communicate with each other using the performSelector:onThread:withObject:waitUntilDone: method. They pass objects between each other passed in as the withObject: parameter of the method.
Sample code is below:
- (BOOL)postMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread.
[self performSelectorOnMainThread:#selector(messageHandler:) withObject:message waitUntilDone:NO];
// message is released here and retain count will be +1 or 0 depending on thread ordering
[message release];
return YES;
}
return NO;
}
- (BOOL)sendMessage:(id <MessageTarget>)sender messageId:(NSInteger)msgId messageData:(void*)data messageResult:(void**)result
{
// message is allocated and retained here. retain count will be +2
Message* message = [[[Message alloc] initWithSender:sender messageId:msgId messageData:data] retain];
if(message)
{
// message will be released in other thread. retain count will be +1 on return
[self performSelectorOnMainThread:#selector(messageHandler:) withObject:message waitUntilDone:YES];
if(result)
*result = [message result];
// message is released here and retain count will be 0 triggering deallocation
[message release];
return YES;
}
return NO;
}
- (void)messageHandler:(Message*)message
{
// message will have a retain count of +1 or +2 in here based on thread execution order
if(message)
{
switch ([message messageId])
{
case
...
break;
default:
...
break;
}
// message is released here bringing retain count to +1 or 0 depending on thread execution ordering
[message release];
}
}
The analyzer is complaining about a possible leak of the Message object allocated in postMessage: and sendMessage: but the object is released in messageHandler:. The code runs correctly and does not leak, and I suspect the analyzer is simply not able to see that the Message object is being released in a different thread.
Now in case you are wondering why I do the second retain in the post/send methods and not in the messageHandler: method, it is because the postMessage: method is meant to be asynchronous and [message release] in the post method may get executed before the [message retain] in messageHandler: would, leaving me with an invalid object. It would work just fine if I did that in the case of the sendMessage: method because it is synchronous.
So is there a better way to do this that would satisfy the memory analyzer? Or maybe a way to give the memory analyzer a hint that the object is in fact being released?
Update:
Torrey provided the answer below but I wanted to clarify what I had to do different from what he suggested.
He suggested using an attribute on my messageHandler: method as below
- (void)messageHandler:(Message*) __attribute__((ns_consumed)) message;
This did not quite work since the object is being passed into performSelector: and the analyzer does not see it being passed along to messageHandler:
Since the performSelector: call is defined by Cocoa and not by me I can not add the attribute to it.
The way around this is to wrap the call to performSelector: as follows:
- (void)myPerformSelector:(SEL)sel onThread:(NSThread*)thread withObject:(id) __attribute__((ns_consumed)) message waitUntilDone:(BOOL)wait;
{
[self performSelector:sel onThread:thread withObject:message waitUntilDone:wait];
}
Then you can call the wrapper function and the analyzer will see the attribute and not complain about an unbalanced retain/release pair.
In the end I did not like the extra indirection just to get rid of the warning so I used the preprocessor as explained in my comment below. But I could see situations where it could be useful to use this method.

You do not need to explicitly transfer reference count ops to the secondary thread when using this API.
a) Your caller holds a reference when waitUntilFinished is true,
b) and the implementation behind + [NSThread performSelector:… also does (see: - [NSRunLoop performSelector:target:argument:order:modes:]).
There is no need to pass reference count duties for the parameters (or self) across threads in this case.
It will either be performed immediately, or self and the parameter (it's objc-typed) will be retained while in the other thread's run loop queue (and self and the parameter are released after the object's performed the selector).
(don't use ref-op __attribute__s to shut it up)

You should be able to make the analyzer happy by judicious use of Clang's ns_consumed attribute. As you suggested, this gives the memory analyzer a hint that a release message will be sent to the parameter upon completion of the function call. You would use it like:
- (void)messageHandler:(Message*) __attribute__((ns_consumed)) message
There is more information on Cocoa memory management annotations in the Clang analyzer documentation. You may want to wrap the attribute setting in an NS_COSUMED macro for compatibility with other compilers as suggested on that page.

Related

passing objects from no arc compiled class to arc enabled class?

I ran into this problem while trying to fix a memory leak with the facebook-ios-sdk. How do i handle this situation when passing objects from no arc compiled classe to arc enabled classe?
This is the code inside the non arc compiled Facebook library: (i removed the unnecessary stuff which is not related to the problem) as you can see, result object is not autoreleased or released.
- (void)handleResponseData:(NSData *)data {
NSError* error = nil;
id result = [self parseJsonResponse:data error:&error];
self.error = error;
// Call the defined delegate wich is my AppDelegate didLoad method wich is arc enabled
[_delegate request:self didLoad:result];
}
- (id)parseJsonResponse:(NSData *)data error:(NSError **)error {
SBJSON *jsonParser = [[SBJSON alloc] init];
//gets the object wich leaks or gets overreleased
id result = [jsonParser objectWithString:responseString];
[jsonParser release];
return result;
}
Now if i try to add autorelease to the result object, i am facing a NSZombie when my arc code in my AppDelegate try's to release the object. However if i leave the code like this i'm facing memory leaks whit the result object which gets not released.
am i missing something basic? i can't get my head around this?
Thanx for any advice! Chris
The result returned from -parseJsonResponse:... is autoreleased already (see note at bottom).
Since the name of the -parseJson method doesn't begin with new, alloc, copy or mutableCopy, the compiler assumes that it returns an object with a +0 reference count, meaning it needs to be retained by the calling code if it is to be kept around, and doesn't need to be released if it's not being kept around. That's a long winded way of saying that it should neither leak nor cause a crash in your ARC code as written in your question.
Passing objects between ARC code and manual reference counting code doesn't require any special handling. You just need to make sure that methods' names match their memory management semantics in the non-ARC code. It certainly seems like you've done that in this case, although as you say, you didn't post your complete code.
Note: Presumably, objectWithString: returns an autoreleased object. If it doesn't it, it should (because it doesn't start with alloc, new, copy, mutableCopy).

Why is #autoreleasepool still needed with ARC?

For the most part with ARC (Automatic Reference Counting), we don't need to think about memory management at all with Objective-C objects. It is not permitted to create NSAutoreleasePools anymore, however there is a new syntax:
#autoreleasepool {
…
}
My question is, why would I ever need this when I'm not supposed to be manually releasing/autoreleasing ?
EDIT: To sum up what I got out of all the anwers and comments succinctly:
New Syntax:
#autoreleasepool { … } is new syntax for
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
…
[pool drain];
More importantly:
ARC uses autorelease as well as release.
It needs an auto release pool in place to do so.
ARC doesn't create the auto release pool for you. However:
The main thread of every Cocoa app already has an autorelease pool in it.
There are two occasions when you might want to make use of #autoreleasepool:
When you are in a secondary thread and there is no auto release pool, you must make your own to prevent leaks, such as myRunLoop(…) { #autoreleasepool { … } return success; }.
When you wish to create a more local pool, as #mattjgalloway has shown in his answer.
ARC doesn't get rid of retains, releases and autoreleases, it just adds in the required ones for you. So there are still calls to retain, there are still calls to release, there are still calls to autorelease and there are still auto release pools.
One of the other changes they made with the new Clang 3.0 compiler and ARC is that they replaced NSAutoReleasePool with the #autoreleasepool compiler directive. NSAutoReleasePool was always a bit of a special "object" anyway and they made it so that the syntax of using one is not confused with an object so that it's generally a bit more simple.
So basically, you need #autoreleasepool because there are still auto release pools to worry about. You just don't need to worry about adding in autorelease calls.
An example of using an auto release pool:
- (void)useALoadOfNumbers {
for (int j = 0; j < 10000; ++j) {
#autoreleasepool {
for (int i = 0; i < 10000; ++i) {
NSNumber *number = [NSNumber numberWithInt:(i+j)];
NSLog(#"number = %p", number);
}
}
}
}
A hugely contrived example, sure, but if you didn't have the #autoreleasepool inside the outer for-loop then you'd be releasing 100000000 objects later on rather than 10000 each time round the outer for-loop.
Update:
Also see this answer - https://stackoverflow.com/a/7950636/1068248 - for why #autoreleasepool is nothing to do with ARC.
Update:
I took a look into the internals of what's going on here and wrote it up on my blog. If you take a look there then you will see exactly what ARC is doing and how the new style #autoreleasepool and how it introduces a scope is used by the compiler to infer information about what retains, releases & autoreleases are required.
#autoreleasepool doesn't autorelease anything. It creates an autorelease pool, so that when the end of block is reached, any objects that were autoreleased by ARC while the block was active will be sent release messages. Apple's Advanced Memory Management Programming Guide explains it thus:
At the end of the autorelease pool block, objects that received an autorelease message within the block are sent a release message—an object receives a release message for each time it was sent an autorelease message within the block.
People often misunderstand ARC for some kind of garbage collection or the like. The truth is that, after some time people at Apple (thanks to llvm and clang projects) realized that Objective-C's memory administration (all the retains and releases, etc.) can be fully automatized at compile time. This is, just by reading the code, even before it is run! :)
In order to do so there is only one condition: We MUST follow the rules, otherwise the compiler would not be able to automate the process at compile time. So, to ensure that we never break the rules, we are not allowed to explicitly write release, retain, etc. Those calls are Automatically injected into our code by the compiler. Hence internally we still have autoreleases, retain, release, etc. It is just we don't need to write them anymore.
The A of ARC is automatic at compile time, which is much better than at run time like garbage collection.
We still have #autoreleasepool{...} because having it does not break any of the rules, we are free create/drain our pool anytime we need it :).
Autorelease pools are required for returning newly created objects from a method. E.g. consider this piece of code:
- (NSString *)messageOfTheDay {
return [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
}
The string created in the method will have a retain count of one. Now who shall balance that retain count with a release?
The method itself? Not possible, it has to return the created object, so it must not release it prior to returning.
The caller of the method? The caller does not expect to retrieve an object that needs releasing, the method name does not imply that a new object is created, it only says that an object is returned and this returned object may be a new one requiring a release but it may as well be an existing one that doesn't. What the method does return may even depend on some internal state, so the the caller cannot know if it has to release that object and it shouldn't have to care.
If the caller had to always release all returned object by convention, then every object not newly created would always have to be retained prior to returning it from a method and it would have to be released by the caller once it goes out of scope, unless it is returned again. This would be highly inefficient in many cases as one can completely avoid altering retain counts in many cases if the caller will not always release the returned object.
That's why there are autorelease pools, so the first method will in fact become
- (NSString *)messageOfTheDay {
NSString * res = [[NSString alloc] initWithFormat:#"Hello %#!", self.username];
return [res autorelease];
}
Calling autorelease on an object adds it to the autorelease pool, but what does that really mean, adding an object to the autorelease pool? Well, it means telling your system "I want you to to release that object for me but at some later time, not now; it has a retain count that needs to be balanced by a release otherwise memory will leak but I cannot do that myself right now, as I need the object to stay alive beyond my current scope and my caller won't do it for me either, it has no knowledge that this needs to be done. So add it to your pool and once you clean up that pool, also clean up my object for me."
With ARC the compiler decides for you when to retain an object, when to release an object and when to add it to an autorelease pool but it still requires the presence of autorelease pools to be able to return newly created objects from methods without leaking memory. Apple has just made some nifty optimizations to the generated code which will sometimes eliminate autorelease pools during runtime. These optimizations require that both, the caller and the callee are using ARC (remember mixing ARC and non-ARC is legal and also officially supported) and if that is actually the case can only be known at runtime.
Consider this ARC Code:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
The code that the system generates, can either behave like the following code (that is the safe version that allows you to freely mix ARC and non-ARC code):
// Callee
- (SomeObject *)getSomeObject {
return [[[SomeObject alloc] init] autorelease];
}
// Caller
SomeObject * obj = [[self getSomeObject] retain];
[obj doStuff];
[obj release];
(Note the retain/release in the caller is just a defensive safety retain, it's not strictly required, the code would be perfectly correct without it)
Or it can behave like this code, in case that both are detected to use ARC at runtime:
// Callee
- (SomeObject *)getSomeObject {
return [[SomeObject alloc] init];
}
// Caller
SomeObject * obj = [self getSomeObject];
[obj doStuff];
[obj release];
As you can see, Apple eliminates the atuorelease, thus also the delayed object release when the pool is destroyed, as well as the safety retain. To learn more about how that is possible and what's really going on behind the scenes, check out this blog post.
Now to the actual question: Why would one use #autoreleasepool?
For most developers, there's only one reason left today for using this construct in their code and that is to keep the memory footprint small where applicable. E.g. consider this loop:
for (int i = 0; i < 1000000; i++) {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Assume that every call to tempObjectForData may create a new TempObject that is returned autorelease. The for-loop will create one million of these temp objects which are all collected in the current autoreleasepool and only once that pool is destroyed, all the temp objects are destroyed as well. Until that happens, you have one million of these temp objects in memory.
If you write the code like this instead:
for (int i = 0; i < 1000000; i++) #autoreleasepool {
// ... code ...
TempObject * to = [TempObject tempObjectForData:...];
// ... do something with to ...
}
Then a new pool is created every time the for-loop runs and is destroyed at the end of each loop iteration. That way at most one temp object is hanging around in memory at any time despite the loop running one million times.
In the past you often had to also manage autoreleasepools yourself when managing threads (e.g. using NSThread) as only the main thread automatically has an autorelease pool for a Cocoa/UIKit app. Yet this is pretty much legacy today as today you probably wouldn't use threads to begin with. You'd use GCD DispatchQueue's or NSOperationQueue's and these two both do manage a top level autorelease pool for you, created before running a block/task and destroyed once done with it.
It's because you still need to provide the compiler with hints about when it is safe for autoreleased objects to go out of scope.
Quoted from https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:
Autorelease Pool Blocks and Threads
Each thread in a Cocoa application maintains its own stack of
autorelease pool blocks. If you are writing a Foundation-only program
or if you detach a thread, you need to create your own autorelease
pool block.
If your application or thread is long-lived and potentially generates
a lot of autoreleased objects, you should use autorelease pool blocks
(like AppKit and UIKit do on the main thread); otherwise, autoreleased
objects accumulate and your memory footprint grows. If your detached
thread does not make Cocoa calls, you do not need to use an
autorelease pool block.
Note: If you create secondary threads using the POSIX thread APIs
instead of NSThread, you cannot use Cocoa unless Cocoa is in
multithreading mode. Cocoa enters multithreading mode only after
detaching its first NSThread object. To use Cocoa on secondary POSIX
threads, your application must first detach at least one NSThread
object, which can immediately exit. You can test whether Cocoa is in
multithreading mode with the NSThread class method isMultiThreaded.
...
In Automatic Reference Counting, or ARC, the system uses the same
reference counting system as MRR, but it insertsthe appropriate memory
management method callsfor you at compile-time. You are strongly
encouraged to use ARC for new projects. If you use ARC, there is
typically no need to understand the underlying implementation
described in this document, although it may in some situations be
helpful. For more about ARC, see Transitioning to ARC Release Notes.
TL;DR
Why is #autoreleasepool still needed with ARC?
#autoreleasepool is used by Objective-C and Swift to work with autorelese inside
When you work with pure Swift and allocate Swift objects - ARC handles it
But if you decide call/use Foundation/Legacy Objective-C code(NSData, Data) which uses autorelese inside then #autoreleasepool in a rescue
//Swift
let imageData = try! Data(contentsOf: url)
//Data init uses Objective-C code with [NSData dataWithContentsOfURL] which uses `autorelese`
Long answer
MRC, ARC, GC
Manual Reference Counting(MRC) or Manual Retain-Release(MRR) as a developer you are responsible for counting references on objects manually
Automatic Reference Counting(ARC) was introduced in iOS v5.0 and OS X Mountain Lion with xCode v4.2
Garbage Collection(GC) was available for Mac OS and was deprecated in OS X Mountain Lion. Must Move to ARC
Reference count in MRC and ARC
//MRC
NSLog(#"Retain Count: %d", [variable retainCount]);
//ARC
NSLog(#"Retain Count: %ld", CFGetRetainCount((__bridge CFTypeRef) variable));
Every object in heap has an integer value which indicates how many references are pointed out on it. When it equals to 0 object is deallocated by system
Allocating object
Working with Reference count
Deallocating object. deinit is called when retainCount == 0
MRC
A *a1 = [[A alloc] init]; //this A object retainCount = 1
A *a2 = a1;
[a2 retain]; //this A object retainCount = 2
// a1, a2 -> object in heap with retainCount
Correct way to release an object:
release If only this - dangling pointer. Because it still can point on the object in heap and it is possible to send a message
= nil If only this - memory leak. deinit will not be called
A *a = [[A alloc] init]; //++retainCount = 1
[a release]; //--retainCount = 0
a = nil; //guarantees that even somebody else has a reference to the object, and we try to send some message thought variable `a` this message will be just skipped
Working with Reference count(Object owner rules):
(0 -> 1) alloc, new, copy, mutableCopy
(+1) retain You are able to own an object as many times as you need(you can call retain several times)
(-1) release If you an owner you must release it. If you release more than retainCount it will be 0
(-1) autorelease Adds an object, which should be released, to autorelease pool. This pool will be processed at the end of RunLoop iteration cycle(it means when all tasks will be finished on the stack)[About] and after that release will be applied for all objects in the pool
(-1) #autoreleasepool Forces process an autorelease pool at the end of block. It is used when you deal with autorelease in a loop and want to clear resources ASAP. If you don't do it your memory footprint will be constantly increasing
autorelease is used in method calls when you allocate a new object there and return it
- (B *)foo {
B *b1 = [[B alloc] init]; //retainCount = 1
//fix - correct way - add it to fix wrong way
//[b1 autorelease];
//wrong way(without fix)
return b;
}
- (void)testFoo {
B *b2 = [a foo];
[b2 retain]; //retainCount = 2
//some logic
[b2 release]; //retainCount = 1
//Memory Leak
}
#autoreleasepool example
- (void)testFoo {
for(i=0; i<100; i++) {
B *b2 = [a foo];
//process b2
}
}
ARC
One of biggest advantage of ARC is that it automatically insert retain, release, autorelease under the hood in Compile Time and as developer you should not take care of it anymore
Enable/Disable ARC
//enable
-fobjc-arc
//disable
-fno-objc-arc
Variants from more to less priority
//1. local file - most priority
Build Phases -> Compile Sources -> Compiler Flags(Select files -> Enter)
//2. global
Build Settings -> Other C Flags(OTHER_CFLAGS)
//3. global
Build Settings -> Objective-C Automatic Reference Counting(CLANG_ENABLE_OBJC_ARC)
Check if ARC is enabled/disabled
Preprocessor __has_feature function is used
__has_feature(objc_arc)
Compile time
// error if ARC is Off. Force to enable ARC
#if ! __has_feature(objc_arc)
#error Please enable ARC for this file
#endif
//or
// error if ARC is On. Force to disable ARC
#if __has_feature(objc_arc)
#error Please disable ARC for this file
#endif
Runtime
#if __has_feature(objc_arc)
// ARC is On
NSLog(#"ARC on");
#else
// ARC is Off
NSLog(#"ARC off");
#endif
Reverse engineering(for Objective-C)
//ARC is enabled
otool -I -v <binary_path> | grep "<mrc_message>"
//e.g.
otool -I -v "/Users/alex/ARC_experiments.app/ARC_experiments" | grep "_objc_release"
//result
0x00000001000080e0 748 _objc_release
//<mrc_message>
_objc_retain
_objc_release
_objc_autoreleaseReturnValue
_objc_retainAutoreleaseReturnValue
_objc_retainAutoreleasedReturnValue
_objc_storeStrong
Tool to Migrate Objective-C MRC to ARC
ARC generates errors where you should manually remove retain, release, autorelease and others issues
Edit -> Convert -> To Objective-C ARC...
New Xcode with MRC
If you enable MRC you get next errors(warnings)(but the build will be successful)
//release/retain/autorelease/retainCount
'release' is unavailable: not available in automatic reference counting mode
ARC forbids explicit message send of 'release'
There seems to be a lot of confusion on this topic (and at least 80 people who probably are now confused about this and think they need to sprinkle #autoreleasepool around their code).
If a project (including its dependencies) exclusively uses ARC, then #autoreleasepool never needs to be used and will do nothing useful. ARC will handle releasing objects at the correct time. For example:
#interface Testing: NSObject
+ (void) test;
#end
#implementation Testing
- (void) dealloc { NSLog(#"dealloc"); }
+ (void) test
{
while(true) NSLog(#"p = %p", [Testing new]);
}
#end
displays:
p = 0x17696f80
dealloc
p = 0x17570a90
dealloc
Each Testing object is deallocated as soon as the value goes out of scope, without waiting for an autorelease pool to be exited. (The same thing happens with the NSNumber example; this just lets us observe the dealloc.) ARC does not use autorelease.
The reason #autoreleasepool is still allowed is for mixed ARC and non-ARC projects, which haven't yet completely transitioned to ARC.
If you call into non-ARC code, it may return an autoreleased object. In that case, the above loop would leak, since the current autorelease pool will never be exited. That's where you'd want to put an #autoreleasepool around the code block.
But if you've completely made the ARC transition, then forget about autoreleasepool.

What is meant by [self release] in Objective-C? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Is calling [self release] allowed to control object lifetime?
What will happen if I use this code snippet?
[self release]
self descrements its own retain count by one, just like release would do with any other object.
The only situation however that I have so far come across, where such a call was appropriate, was the case where an init… method would fail and be expected to return nil and deallocate the just allocated instance.
In 9 out of 10 situations you shouldn't use [self release], I'd estimate.
Something like this (which basically forbids the calling of - (id)init;, for cases where you want to force the use of a particular - (id)initWith… method.):
- (id)init {
[self release];
NSString *reason = [NSString stringWithFormat:#"%# is not a valid initializer for the class %#", NSStringFromSelector(_cmd), NSStringFromClass([self class])];
#throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:reason
userInfo:nil];
return nil;
}
or this (which basically enforces the proving of an object on initialization)
- (id)initWithFoo:(Foo *)foo {
if (!foo) {//foo is required to be non-nil!
[self release];
return nil;
}
//proceed with initialization
return self;
}
These however are not the only ever occasions where [self release] would be appropriate. But merely the ones I've come across so far. (as Oliver correctly pointed out)
Edit: Self-invalidating NSTimers would probably be another (quite common, yet somewhat special) situation.
You will release yourself, what means that the object declares itself that it does not have to still live. If no one else retains tha object, it dies and its memory is freed
You have little reasons to do that, except if you want to create object that are not controlled by anyone else and are self controlled.
I mean, for example, there is the case where you may want to create an self living object that makes some treatments, and suicide when it has finished without having to tell anyone else it has finished.
Let's imagine for example a class whose purpose is just to send a message to a server :
You instanciate the class, as soon as it is istanciated it send a message to a server, it waits for the server answer, and if the answer is ok, it suicide. That way, you don't have to manage any server answer from within another class controller whose purpose is not to manage such events.
It just decrements the receiver’s reference count.

Incorrect decrement error, code review

This code down below works as expected, cleans things up without Zombies. The class in which this method exists, is the owner of the Nodes, which are being released, yet, upon "Analyze" the following 2 issues show up.
If possible, could you help me understand why?
- (void) dealloc {
NSLog(#"Releasing [Doubly Linked List] .. ");
Node *thisNode = [self firstNode];
Node *nextNode = [thisNode next];
while (nextNode != nil) {
// If "Next node" is not nil, it means that
// "previous node" can now be released
NSLog(#" - releasing node \"%c\"", [[nextNode previous] charData]);
[[nextNode previous] release];
nextNode = [nextNode next];
}
[[self lastNode] release];
[super dealloc];
}
Click on the icon on the left of the message, it will show the path through the code that produces the error.
You are releasing something, [nextNode previous] that you do not own. In particular you did not alloc or retain it nor obtain it from a method that begins with new or copy so you do not have ownership of it and should not release it.
It is also very uncommon to release something not in your class, [[nextNode previous] release].
Now: [[self lastNode] release];
As above you did not obtain an ownership on the object you are releasing.
If lastNode is a property with retain you are subverting the setter and when later a value is assigned to lastNode via the setter there will be an extra release on the object and probably a crash. If it is not a property again this it very non-standard to release something that is returned by a method call.
Any releases with code of this form [[self lastNode] release] is non-standard and if be avoided there will be fewer ownership (retain/release) problems.
You will save a lot of time and grief by studying the Apple memory management documentation.
The issue is that you are not doing things according to the ordinary memory management conventions of Objective C and the static analyzer is getting confused. Basically, the Objective C class which allocates an object "owns" the object and is responsible for releasing it. Here, you are not using those conventions, so the analyzer is complaining, even if what you are doing works correctly.
See Apple's documentation for more on ownership.

NSOperation not being fully deallocated? Live Bytes not less than Overall Bytes in Allocations Utility despite operations completing

I'm running a large number of NSOperation tasks and my application is using a great deal of memory. While it should use quite a bit, it's using magnitudes more than it should, and I'm thinking, from Instruments, that it's because the NSOperation objects aren't being fully deallocated. The code for my NSOperation subclass is as such:
- (id)initFromNode:(BKObject *)sender withNumber:(NSNumber *)number; {
self = [super init];
if (self) {
_number = [number retain];
_sender = [sender retain];
}
return self;
}
- (void)main {
[_sender go:_number];
}
- (void)dealloc {
[_number release];
_number = nil;
[_sender release];
_sender = nil;
[super dealloc];
}
My suspicions are as such because in Instruments, when I use the Allocations utility, it shows enormous amounts of data for my _NSOperationInternal and also my subclasses of NSOperation, but the Live Bytes number is always equal to the Overall Bytes number. I've also checked with the Leaks utility, which never finds any memory leaks. I'm careful about releasing any operation objects after adding them to the queue.
I also stuck in a completion block to test it out if it actually finishes, and I can confirm that at least some of them do. Confirming all of them would be more work, and the live data in Instruments should go down a bit, even if only, say 10% of them, were finishing.
I'm at a loss. Let me know if any of my understanding of what I'm doing is off or if more code would be helpful. Do you know what might be going on that this is using more memory than it should?
To debug this, try to see if -dealloc gets even called. The simplest way to do this is to use an NSLog, the correct way would be a breakpoint.
My guesses are:
You're not correctly releasing the NSOperations.
or you've got retain cycles.
Some objects in your NSOperation don't get released, try adding an autorelease pool around your main method.