Re: Problem with garbage collection in server application
Re: Problem with garbage collection in server application
- Subject: Re: Problem with garbage collection in server application
- From: Rick Hoge <email@hidden>
- Date: Sat, 22 Jan 2011 23:27:32 -0500
On 2011-01-20, at 10:54 AM, Rick Hoge wrote:
[...]
> I have overridden the 'finalize' method of the dataset class to print a log message before calling [super finalize], and when I perform a single processing 'run' in which the client sends a message to the server directing it to load a 200MB dataset and then perform a series of processing operations which result in five datasets being open, I have noticed that - while the finalize methods are indeed called - they are called around five to ten seconds after the last processing directive is sent from the client.
> For five datasets the above behaviour is not a problem, but in more realistic tests where we generate five datasets, flush, then generate five more, before repeating the cycle perhaps 10 times, the finalize methods never appear to be called (or at least no log messages appear). The memory usage becomes huge, and eventually the program crashes.
I worked up a version of our app that uses retain/release style memory management, and was surprised to note that a similar thing was happening (although the memory use did not get as big). Running a script that would send five sequential processing requests to the server, with a 'close all' at the end, would result in immediate deallocation of all five datasets. However if I put the script commands inside a for loop (scripted to repeat two or more times), then the datasets are not deallocated until the end of all loops. I put a breakpoint on 'retain' in my dataset objects, and it's clear that they are getting a lot of retains from various observer objects in the user interface used to monitor script execution. The UI objects must be getting dealloc'ed themselves, as the dataset objects are eventually released.
I noticed that if I put a 'sleep 1' at the bottom of the loop in my shell script, then the dataset objects would indeed be deallocated at the bottom of the loop (not after all loops). So it might be that all the KVO stuff for the UI is getting cleaned up very late in the run loop, in a process that is interrupted by another message to the NSConnection immediately upon exit.
After seeing this in the retain/release version, I then tried running the GC version with the 'sleep 1' at the bottom of the loop. Lo and behold, the objects were getting finalized at the bottom of each loop (slightly asynchronously from the main thread, but that's fine). A number of tests also showed that the GC version ran around 10% faster for long processing runs.
So maybe all this is a symptom of an uncontrolled interaction between the NSConnection I use to run client requests, and the NSRunLoop that is associated with the UI. Perhaps I should be looking for some way to force the app to wait until the end of the current runloop before accepting another message on the NSConnection, but I'm not sure how to do that.
Of course I could also just put a sleep(1); in the code after removing references to the dataset objects and calling collectExhaustively, but this seems pretty crude and who knows if 1 second will be long enough for some ultra-large processing run (although it works just as well as a shell sleep in my test runs).
I was very close to giving up on GC, but maybe this is a vital clue. It was certainly not fun to add all the dealloc methods for my limited testing...
Thanks again for any help,
Rick
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden