Detecting memory leaks

KenDRhyD

Registered
Are there any tools that will report memory leaks in Objective-C/Cocoa code?

I have tried MallocDebug but it did not seem to tell me anything. I find it difficult to belive that I have programmed the applications without leaks or extra releases the very first time by accident!

-ken
 
kainjow said:

Man this is tough going!!!

I followed the instructions noted in the link above, and it confirmed that there were some leaks in my code, but it is not trivial to track them down, especially when a number of them are simply blobs of memory or NSCFString objects, which I do not create directly. It is also frustrating that this information is only available when the application is executing.

I really miss something like the BoundsChecker product that is available for Visual Studio (working on the dark side pays the bills), which produces a list of leaked objects when the application terminates. It seems to do this by hooking the 'malloc' and 'new' logic and recording when objects are allocated and when they are released. In debug mode this can even report the line of code that allocated the memory!

So, I found a couple of legitimate leaks and fixed them, but somewhere along the line I somehow released an object (or more than one) when I should not have, and now the application drops into the debugger in the autorelease logic! I cannot figure out which of the rather large number involved may be causing the problem!

Any ideas on how I can isolate this? Other than by brain damaging my code to the point where it does next to nothing and then start building it up again until I trip over the problem?
 
I have been arduously working through all of the existing code attempting to isolate the cause of my programming error. By inserting a large number of NSLog() calls and including the [retainCount] value for various objects at different points, I was able to identify some places where the count was too high and the objects were not being released.

Unfortunately, I seem to have triggered the opposite effect -- now there is some object that is being autoreleased when I do not expect it to be, and program is crashing in assembler code that implies that a AppKit autorelease pool is attempting to release an object that has already been released.

The problem is that I cannot tell which object it is attempting to release.

I can stop the problem from occurring by commenting out one line of my code that manually releases an object, but that object was [alloc] by me and I did not indicate that it should be autoreleased, so this does not make sense.

I also have NSLog() calls in all of the [dealloc] methods for all of my objects, so it does not appear that the problem is a nested auto-release.

The [retainCount] value is extremely useful, but I can find no way to determine whether or not a specific object is set for autorelease or not. Is there a way to determine this?

Any other thoughts on how I can track down the cause of these reference count problems?
 
You could try posting some code up. More eyes the better....

Apart from that crawl over all your -init and -dealloc methods. I made a silly mistake where I was not calling super once ....
 
boyfarrell said:
You could try posting some code up. More eyes the better....

Apart from that crawl over all your -init and -dealloc methods. I made a silly mistake where I was not calling super once ....

I am more than willing to provide a copy of the entire project to anyone who is interested (it is an Objective-C wrapper for SQLite). If you want a copy, let me know where to send it.

I currently have three different problems:

1. There are still some places where there are too many retain counts so the objects are legitimately leaking; I have been tracking these down slowly.

2. For some reason the code is now crashing on a signal 10. Previously it was failing on an Pop release pool actiion. I suspect I am releasing something that is then being referenced rather than autoreleased and hence the change in behaviour, but I have not found it yet.

3. I have a weird situation where I place some object in an NSMutableArray, and they all have a reference count of 1. I pass then into an initializer for another class and use the array to initialize an NSArray; they now all have a count of 2. I make a pass through the array using an enumerator to set a non-retained reference object, and somehow the last item in the last magically gets a reference count of 3!

This last item has had me stumped for a while (had to take a break to do some spouse-approved activities), and I have not made much progress on the other issues.

The code is a bit of a mess right now since I have been adding NSLog() calls all over the place and commenting out parts of the code in an attempt to isolate specific problems and solve them (divide and conquer).
 
The xcode debugger should usually help in tracking down where the crash is occuring. adding break points and inspecting the retain count and value of the objects just before the crash can be helpful too.
The main NSEnumerators retain each item while it is being enumerated. Make sure to enumerate through all of the objects, or wait until the enumerator is autoreleased to re-check the retain count on the objects in the enumerator collection.
 
epooch said:
The xcode debugger should usually help in tracking down where the crash is occuring. adding break points and inspecting the retain count and value of the objects just before the crash can be helpful too.
The main NSEnumerators retain each item while it is being enumerated. Make sure to enumerate through all of the objects, or wait until the enumerator is autoreleased to re-check the retain count on the objects in the enumerator collection.
With respect to the enumerator, I am using as in the example in the documentation:
Code:
NSEnumerator*	e = [_Columns objectEnumerator];
MyColumn*	col = nil;

while ((col = [e nextObject]) != nil)
{
}

Note that I do not even execute any code inside the loop at this time (I removed it to see if that was causing the problem, and it is not). Much later in the process when it is time to release the owning object -- MyResult --> NSArray(MyColumns) -- the retain count on all of the MyColumn objects is 1 except for the last one added, which is 2.

If I comment out the use of the enumerator, then the retain count is 1 on the last object.

As I was modifying my code, the original 'crash' changed. For a time the code was reporting that there was a null path to the executable and the cxrash was a signal 11. That may have been caused by my releasing the enumerator myself, because when I put the code back to match the usage in the documentation as noted above, the old crash is back. The crash is all in assembler and the following is the call stack:
Code:
obj_msgSend_rtp
NSPopAutoreleasePool
-[NSApplication run]
NSApplicationMain
main
I suspect that the problem is that I am releasing an object that is marked for autorelease, but I cannot determine which one it may be!
 
Back
Top