Live object is garbage collected? - objective-c

I am using Garbage collector in my Cocoa based application on Mac OS X. It has 100s of threads running and synchronization is done using Operation Queue.
After a long run, one of the object is garbaged and application will crash.
Checking to see if the object is non nil also fails as the the object is invalid and contains some garbage value. Calling a method on the object leads to crash.
Anyone please help me in debugging the issue.
Thank you......................

I am using Garbage collector in my
Cocoa based application on Mac OS X.
It has 100s of threads running and
synchronization is done using
Operation Queue.
More likely than not, the bug lies within the seemingly rather overly concurrent nature of your code. Running 100s of threads on a machine with "only" double digits worth of cores (if that) is unlikely to be very efficient and, of course, keeping everything properly in sync is going to be rather difficult.
The best place to start is to turn on Malloc stack logging and use malloc_history to find out what events occurred at the address that went south.
Also, there were fixes in 10.6.5 that impacted GC correctness.

If you can change the code of the garbage collected object, then override the finalize method like this, to get some information:
- (void) finalize
{
NSLog(#"Finalizing!\n%#", [[NSThread callStackSymbols] componentsJoinedByString:#"\n"]);
//if you put here a breakpoint, you can check the supposed references to this object
[super finalize];
}

Related

What can cause different ObjC/ARC memory behaviour between Release and Debug configuration?

I was running a test to make sure objects are being deallocated properly by wrapping the relevant code section in a 10 second long while loop. I ran the test in Debug and Release configurations with different results.
Debug (Build & Run in simulator):
Release (Build & Run on device, and Profile using Instruments):
The CPU spikes signify where objects are created and destroyed (there's 3 in each run). Notice how in the Debug build, the memory usage rises gradually during the busy loop, and then settles a little afterwards at a higher base level, this happens with each loop iteration. On the Release build it stays constant the whole time. At the end after 3 runs the memory usage level of the Debug build is significantly higher than that of the Release build. (The CPU spikes are offset on the time axis relative to each other but that's just because I pressed the button that triggers the loop at different times).
The inner loop code in question is very simple and basically consists of a bunch of correctly paired malloc and free statements as well as a bunch retain and release calls (courtesy of ARC, also verified as correctly paired).
Any idea what is causing this behaviour?
In Release builds ARC will do its best to keep objects out of the autorelease pool. It does this using objc_returnsRetainAutorelease and checking for it at runtime.
A lot of Cocoa-Touch classes use caching to improve performance. Memory amount used for caching data could vary depending on total memory, available memory and probably some other things. Since you compare results for Mac and device it is not strange that you receive different results.
Some examples of classes/methods that use caching:
+(UIImage *)imageNamed:(NSString *)name
Discussion
This method looks in the system caches for an image object with the specified name and
returns that object if it exists. If a matching image object is not
already in the cache, this method loads the image data from the
specified file, caches it, and then returns the resulting object.
NSURLCache
The NSURLCache class implements the caching of responses to
URL load requests by mapping NSURLRequest objects to
NSCachedURLResponse objects. It provides a composite in-memory and
on-disk cache
For one thing, the release builds optimize code and remove debugging information from the code. As a result, the application package is significantly smaller and to load it, less memory is necessary.
I suppose that most of the used memory in Debug builds is the actual debugging information, zombie tracking etc.

Best place to clean-up App global resources?

STOP PRESS OK before you see the word retainCount in the following question, please skip to the EDIT at the bottom where I have stated that I have stopped using it.
My Cocoa App, which uses MRR, creates many global resources, which I am loading in main(), before NSApplicationMain() is called. As NSApplicationMain() doesn't return, I have hooked the clean-up of these resources using atexit(), like this:
atexit(cleanup);
if (![CocoaUtil initCocoaUtil] ||
![PreferenceController initPreferenceController] ||
![ResourceManager initResourceManager])
{
criticalAlertPanel(#"Failed to initialize application",
#"Failed to initialize application");
return 4;
}
retval = NSApplicationMain(argc, (const char **)argv);
However cleanup() is getting called before any of the views in my NSDocument subclass are dealloc'd (I have lack of log message to show this) and hence the reference counts of the objects in the global resources is sometimes > 1. I am being over-cautious and attempting to pre-empt memory leaks by using this method to release my global resources:
+ (void)fullRelease:(id)obj
format:(NSString *)format, ...
{
if (obj == nil)
return;
NSUInteger retainCount = [obj retainCount];
if (retainCount > 1)
{
va_list va;
va_start(va, format);
NSString *objDesc = [[NSString alloc] initWithFormat:format arguments:va];
logwrn(#"%# has a reference count of %lu", objDesc, retainCount);
[objDesc release];
}
while (retainCount > 0)
{
[obj release];
retainCount--;
}
}
My log shows the following:
12:15:04.954 INF -[AppController applicationDidFinishLaunching:] Application launched
12:15:06.702 INF -[AppController applicationShouldTerminate:] Application terminating
12:15:06.703 INF -[AppController applicationWillTerminate:] Application terminating
12:15:06.705 DBG cleanup Cleaning-up
12:15:06.705 INF +[ResourceManager finiResourceManager] Cleaning up
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[2] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[3] has a reference count of 2
12:15:06.709 WRN +[CocoaUtil fullRelease:format:] _images[4] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[5] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[6] has a reference count of 2
12:15:06.710 WRN +[CocoaUtil fullRelease:format:] _images[7] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[8] has a reference count of 2
12:15:06.711 WRN +[CocoaUtil fullRelease:format:] _images[9] has a reference count of 2
12:15:06.721 DBG +[PreferenceController finiPreferenceController] Cleaning up
12:15:06.721 DBG +[CocoaUtil finiCocoaUtil] Cleaning up
My question (finally!) is:
Is there a way to ensure I clean-up my global resource after all the NSDocument instances have been destroyed and stop getting these false negatives?
EDIT: I have unhooked the fullRelease call and just performed a normal release on my resources and Instruments did not detect any memory leaks, so things are OK, but I am curious as to why the NSDocument objects don't appear to be being released before atexit() is called.
Do not release something you do not own!
Every retain belongs to somebody else. Only send release to an object to balance your calls to new, alloc, copy, or retain (NARC.) This sort of behaviour will inevitably cause a crash in production code.
It looks like you want to make sure an object is deallocated rather than simply taken care of. If you own the object, release it once; the other references to it belong to other objects. It's possible you do have memory leaks in your code (we can't tell just from this code sample) but those can usually be found with the Static Analyzer, Instruments, and a bit of elbow grease.
More importantly: the operating system will free all your memory for you when your process exits. This is not part of the C standard but it is simply how OS X and iOS operate, and it is the expected behaviour on other platforms that support Objective-C. So you don't have to do anything special to clean up when your process exits, except perhaps writing files to disk or similar. In fact, many Cocoa applications don't bother to release anything owned by their app delegates, because it's faster to let the operating system dump the memory than it is to call -release on thousands of objects.
Do not call -retainCount!
It lies. Plain and simple. It includes temporary references used by Cocoa, most importantly, and you should never attempt to interfere with those. -retainCount is a poisoned symbol.
Some notes:
don't use retainCount; see the links on http://whentouseretaincount.com for lots of details
atexit() handlers are useless in high level programming. When called, the app is in a relatively undefined state. The frameworks will have torn down some stuff but, as you noted, there will be a ton of objects that will never be deallocated. atexit() may not be called at all, in some cases.
you cannot rely on app termination to do any kind of required state cleanup. The user may force quit your app. The system might, too, or it might be force-rebooted. At-termination behavior should be treated as an optimization; can you do some stuff that'll make the next launch faster.
during app termination, there is no need to deallocate anything. The system will reclaim all app resources upon termination, regardless of app state. In other words, objects left in memory at termination are not leaks.
in general, the "Leaks" detection tools can only be used to fix obvious problems. Leaks only detects memory leaks. It cannot detect memory accretion where the objects accreted are still connected to a global somehow. Accretion aren't technically leaks, but they can easily be a huge source of problems.
HeapShot analysis will detect both leaks and memory accretion.
Consider migrating your app to use ARC. One of the guiding patterns of ARC is that the compiler has complete knowledge of the lifespan of objects. Expressions that are ambiguous under MRR are disallowed under ARC (without proper markup, in some cases). As well, the ARC compiler and analyzer can do a much deeper analysis of your code, finding many issues that can be quite subtle.
Disable sudden termination, don't use globals, and just use the regular reference counting rules. In some cases, you will need to break strong circular references or manually clear out your objects' instance variables. Finally, it may be more helpful to pause/break before main returns, and run heap to see what's really alive (a leak) at this stage.
I am being over-cautious and attempting to pre-empt memory leaks by using this method to release my global resources.
You should not purge like this - you know better :)
However, locating and destroying all references/objects/allocations which you have control over is actually a very good practice, to ensure your programs work well, are reusable, and as good metrics for monitoring regressions as your apps change.
As all the others have said: Release only what you own. Your app may not crash for you now, but you're just getting lucky. It may crash on another Mac when you do this, or in two hours, or whatever.
If you have a scarce resource that some object is holding on to that really needs to be unregistered from (e.g. a network session to another server, where not correctly sending it a sign-off message will cause the server to wait for you, keeping some internal state for your return), you should build that into your objects instead of doing that when your objects are released.
E.g. there is a notification that Mac OS X sends before your application quits, NSApplicationWillTerminate. Have your object register for that, and when it gets it, have it send the server its goodbye (and remember that it already did that). That way, when your application quits, but e.g. the application delegate is still holding on to that object, you're still sure that the sign-off will happen.
But you should probably still also check if you've signed off already in -dealloc. One day you might add support for multiple servers, and then when you release one server, you want it to send a goodbye even though your app will not quit. But only do the sign off if you haven't done it already.
Same goes for when you have some data in memory that you want to write down before you quit (e.g. that's what NSUserDefaults does to make sure access to preferences is fast, but it still gets written to disk before you quit).
But cases like that are REALLY rare. Usually NSDocument will call you to write to disk when needed, and generally servers notice when the connection drops and clean up by themselves. So you really shouldn't release stuff that doesn't belong to you. You'll just cause crashes on quit for some of your users. It gives a really bad impression, and can cause your app to actually fail before it got the chance to save some data, and as such make things worse.

Why does garbage collection not work with threads?

Every thing works fine in my app up until I detach a thread to read audio data out of a file and process it.
Garbage Collection seems to not know anything about what happens on this thread no matter what I do. I've tried [NSThread self], [NSThread currentThread], [[NSGarbageCollector defaultCollector]collectIfNeeded] and collectExhaustivly].
I switched to NSOperation with NSOperationQueue from NSThread.
None of these suggested solutions have worked. Most recently, I switched from NSMutableArrays to
Float32* pfArray= calloc(numFloats, sizeof(Float32));
to hold my data, and used
free(pfArray);
to free that memory. This is working better, but still leaking a decent amount.
Garbage Collection does seem to start working to some extent after the "real mem" indicated in Activity Monitor hits some arbitrary number, but when it does appear to be working, it does NOT free all the memory being used. It just doesn't let it go much higher than the arbitrary threshold.
I've read that GC is the way to go, but now I'm unsure and have an almost fully written program. Any suggestions would be very helpful. Thank you!
Garbage collection indeed works on all threads of the app. You might have unwittingly kept a reference to some object rooted, thus leaking a subgraph; without the original code, however, not much can be said.
“collectIfNeeded” implies that it will not collect if collection isn't needed.
Use Instruments's Heapshot feature (part of the Allocations instrument) to find out what objects are remaining alive, and its Object Graph instrument to find out what is still holding on to the objects that you think should no longer be needed.

GC on unregistered thread in a Core MIDI callback

I am just getting started again with Mac development.
I am using CoreMIDI which is a C API which allows me to define a C callback function to be called from the MIDI server on a separate thread whenever a MIDI message arrives. The registration of this callback is done in Objective-C/C code triggered by an awakeFromNib call.
It seems to work fine, except when I get my first callback I get the following warning message on the console:
MidiList(6685,0x103ddb000) malloc: *** auto malloc[6685]: error: GC operation on unregistered thread. Thread registered implicitly. Break on auto_zone_thread_registration_error() to debug.
I read up on this online and it sounds like a harmless error. But the weird thing to me is I don't understand how a "GC operation" occurred? My project does have GC enabled, but I thought that was only for the Cocoa parts. And my callback doesn't use any Cocoa code, it is just a free function which uses some CoreMIDI and CoreFoundation functionality (including CFSTR if that matters). Why would a GC operation occur on that thread if i'm not using any Cocoa objects?
Because the garbage collector doesn't know you're not using Cocoa on this thread.
The garbage collector that Cocoa sports is a conservative garbage collector: it actually knows next to nothing about how your program is structured. All it does is scanning the stack of each thread, and objects on the heap, for bit patterns that look like pointers, and if there's an object at this would-be location, it keeps it alive.
There is, obviously, a possibility for false positives. You can have an integer that has a value looking like a pointer and the garbage collector will believe it's one.
Besides, you may allocate garbage-collected memory in a malloc-like way with NSAllocateCollectable. The GC must take them into account too, especially since the returned pointer could be passed into C code that's not even aware of garbage collection.
EDIT Aside from NSAllocateCollectable, Core Foundation objects (CF-prefixed types) can be made garbage-collected with the help of CFMakeCollectable. Once it's used, the garbage collector will take care of them.
If you are creating pthread, add this objc_registerThreadWithCollector(); to your pthread.
In case you cannot find a symbol or linking error, use following code,
#include <dlfcn.h>
void (*registerThreadWithCollector_fn)(void);
registerThreadWithCollector_fn = (void(*)(void)) dlsym(RTLD_NEXT, "objc_registerThreadWithCollector");
if (registerThreadWithCollector_fn) {
(*registerThreadWithCollector_fn)();
} else {
// do something else
}

Track all Objective-C's alloc/allocWithZone/dealloc

Sorry for long description, however the questions aren't so easy...
My project written without GC. Recently I found a memory leak that I can't find. I did use new Xcode Analyzer without a result. I did read my code line by line and verified all alloc/release/copy/autorelease/mutableCopy/retain and pools... - still nothing.
Preamble: Standard Instruments and Omni Leak Checker don't work for me by some reason (Omin Tool rejects my app, Instruments.app (Leaks) eats too many memory and CPU so I have no chance to use it).
So I wanna write and use my own code to hook & track "all" alloc/allocWithZone:/dealloc messages statistics to write some simple own leaks checking library (the main goal is only to mark objects' class names with possible leaks).
The main hooking technique that I use:
Method originalAllocWithZone = class_getClassMethod([NSObject class],#selector(allocWithZone:));
if (originalAllocWithZone)
{
imp_azo = (t_impAZOriginal)method_getImplementation(originalAllocWithZone);
if (imp_azo)
{
Method hookedAllocWithZone = class_getClassMethod([NSObject class],#selector(hookedAllocWithZone:));
if (hookedAllocWithZone)
{
method_setImplementation(originalAllocWithZone,method_getImplementation(hookedAllocWithZone));
fprintf(stderr,"Leaks Hook: allocWithZone: ; Installed\n");
}
}
}
code like this for hook the alloc method, and dealloc as NSObject category method.
I save IMP for previous methods implementation then register & calculate all alloc/allocWithZone: calls as increment (+1) stat-array NSInteger values, and dealloc calls as decrement (-1).
As end point I call previous implementation and return value.
In concept all works just fine.
If it needs, I can even detect when class are part of class cluster (like NSString, NSPathStore2; NSDate, __NSCFDate)... via some normalize-function (but it doesn't matter for the issues described bellow).
However this technique has some issues:
Not all classes can be caught, for
example, [NSDate date] doesn't catch
in alloc/allocWithZone: at all, however, I can see alloc call in GDB
Since I'm trying to use auto singleton detection technique (based on retainCount readind) to auto exclude some objects from final statistics, NSLocale creation freezes on pre-init stage when starting of full Cocoa application (actually, even simple Objective-C command line utility with the Foundation framework included has some additional initialization before main()) - by GDB there is allocWithZone: calls one after other,....
Full Concept-Project draft sources uploaded here: http://unclemif.com/external/DILeak.zip (3.5 Kb)
Run make from Terminal.app to compile it, run ./concept to show it in action.
The 1st Question: Why I can't catch all object allocations by hooking alloc & allocWithZone: methods?
The 2nd Question: Why hooked allocWithZone: freezes in CFGetRetainCount (or [inst retainCount]) for some classes...
Holy re-inventing the wheel, batman!
You are making this way harder than it needs to be. There is absolutely no need whatsoever to roll your own object tracking tools (though it is an interesting mental exercise).
Because you are using GC, the tools for tracking allocations and identifying leaks are all very mature.
Under GC, a leak will take one of two forms; either there will be a strong reference to the object that should long ago been destroyed or the object has been CFRetain'd without a balancing CFRelease.
The collector is quite adept at figuring out why any given object is remaining beyond its welcome.
Thus, you need to find some set of objects that are sticking around too long. Any object will do. Once you have the address of said object, you can use the Object Graph instrument in Instruments to figure out why it is sticking around; figure out what is still referring to it or where it was retained.
Or, from gdb, use info gc-roots 0xaddr to find all of the various things that are rooting the object. If you turn on malloc history (see the malloc man page), you can get the allocation histories of the objects that are holding the reference.
Oh, without GC, huh...
You are still left with a plethora of tools and no need to re-invent the wheel.
The leaks command line tool will often give you some good clues. Turn on MallocStackLoggingNoCompact to be able to use malloc_history (another command line tool).
Or use the ObjectAlloc instrument.
In any case, you need to identify an object or two that is being leaked. With that, you can figure out what is hanging on to it. In non-GC, that is entirely a case of figuring out why it there is a retain not balanced by a release.
Even without the Leaks instrument, Instruments can still help you.
Start with the Leaks template, then delete the Leaks instrument from it (since you say it uses too much memory). ObjectAlloc alone will tell you all of your objects' allocations and deallocations, and (with an option turned on, which it is by default in the Leaks template) all of their retentions and releases as well.
You can set the ObjectAlloc instrument to only show you objects that still exist; if you bring the application to the point where no objects (or no objects of a certain class) should exist, and such objects do still exist, then you have a leak. You can then drill down to find the cause of the leak.
This video may help.
Start from the Xcode templates. Don't try to roll your own main() routine for a cocoa app until you know what you're doing.