Hi Quincey,

The way you broke this down was very helpful, and it turned out to be a 
combination of two things you alluded to.  I'd been on the right track that it 
had to do with NIB objects, and thinking about it as you laid out helped 
identify the problem.

On 2011-01-23, at 12:28 AM, Quincey Morris wrote:

> 1. Too much "live" (i.e. uncollectible) data at once. This breaks down into 
> three subcategories:
> 
> 1a. Objects that you create, and keep strong references to, use too much 
> memory in total.
> 
> 1b. Your code depends on a confusion between the end of the lifetimes of your 
> objects and the collection times of the memory they use. You shouldn't be 
> designing with collection times in mind.
> 
> 1c. Objects that are created by the frameworks internally, but which somehow 
> support objects that you create (think of a cache, for example), have 
> lifetimes not under your control, and remain live after your own objects' 
> lifetimes are over.

I think it's mostly 1c.

So in the end the problem was that I had some NIB files with NSArrayControllers 
bound to my 'datasets' array.  The large dataset objects are removed from the 
array when I am done with them, and since this constitutes the last strong 
reference I'd (deliberately) created I expected them to be eligible for 
collection.  However I initially assumed that removing the objects from the 
array would also remove any references in bound NIB objects right away.  This 
turned out to be the source of what to me was unexpected behaviour.  Although 
the UI objects seem to be removed from the view on cue, it's up to the 
collector when they will actually be reaped.  As soon as my server app exits 
the method invoked by the client via an NSConnection, there is typically 
another message waiting that gets executed right away.  This seems to block 
collection of the UI objects, which must have strong references to my dataset 
objects.  The UI objects only get collected after the last message is sent from 
the client, and the server resumes the 'waiting for user input' state.

In my app the UI content that is bound to attributes of the datasets is largely 
for logging purposes, and I can just as easily bind to an array of lightweight 
proxy objects that have all of the relevant information.  As soon as I removed 
the single binding of an NSArrayController to my 'datasets' array, the objects 
were collected pretty much right away (right after collectExhaustively).

Now I know I shouldn't be thinking about collection times, but now I think I 
understand the problem better.  By creating strong references between NIB 
objects and my internal objects, I no longer had control of the last strong 
reference to the object.  The rapidly successive client connections to the 
server in script mode were blocking collection of the UI objects, guaranteeing 
that all of the large dataset objects would be kept alive as long as the script 
was running.  After removing direct NIB bindings to the dataset objects, the 
memory usage behaves exactly as expected.

This all jives with a clue I'd noticed all along - the server app basically 
manipulates two types of object:  datasets, and processing operations.  From 
the start I had been binding the UI to lightweight proxies of the processing 
operations.  I'd noticed that the processing operations had always been 
collected very promptly after the last reference was removed.  Now it makes 
perfect sense!

Oh garbage collector, I am sorry that I ever doubted you...

Rick


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to