Re: dealloc and scarce resources
Re: dealloc and scarce resources
- Subject: Re: dealloc and scarce resources
- From: James Merkel <email@hidden>
- Date: Wed, 29 Jun 2011 20:41:27 -0700
On Jun 29, 2011, at 7:17 PM, Wim Lewis wrote:
On 29 Jun 2011, at 5:43 PM, James Merkel wrote:
In the [Memory Management Programming Guide] it says:
"You should typically not manage scarce resources such as file
descriptors, network connections, and buffers or caches in a
dealloc method. In particular, you should not design classes so
that dealloc will be invoked when you think it will be invoked.
Invocation of dealloc might be delayed or sidestepped, either
because of a bug or because of application tear-down.
Instead, if you have a class whose instances manage scarce
resources, you should design your application such that you know
when you no longer need the resources and can then tell the
instance to “clean up” at that point. You would typically then
release the instance, and dealloc would follow, but you will not
suffer additional problems if it does not."
In my code I close a file in the dealloc method -- so I guess
that's a file descriptor. I opened the file in the init method, so
it seemed logical to close it in the dealloc method.
Also, not to be facetious, if I have a bug in my code, wouldn't I
fix it? Granted, at application tear-down, if the file is still
open, it won't be closed because dealloc won't be called. But again
that comes under the heading of a bug in the code. So I don't
understand this injunction.
I don't think it should be treated as a hard rule, but I think it is
good advice most of the time, or at least a good starting position.
One way to look at it is that for most objects you're not supposed
to assume very much about their lifetime. You know they exist as
long as you have a refcount to them, but they *may* continue to
exist after you release them. This is the semantic of -release. You
may happen to know, in a particular piece of code, that you have the
only reference to something and it will be dealloced with a given
release. But thinking of release as equivalent to dealloc will get
you into trouble.
Even ignoring GC (which makes dealloc/finalize even more uncertain),
you might end up stashing a reference to that object somewhere else,
extending its lifetime. Maybe it's in an NSNotification or an undo
stack or a debug log, or there's a situation where your autorelease
pool lasts longer than you expect (perhaps you are dealing with a
bunch of files in a loop as you load or save a document, eg). In my
experience it isn't *usually* a problem of leaking the file handles
entirely; it's a problem if I temporarily accumulate too many of
them, or if I need the file handle (or socket or...) to be closed
before I do some operation, and simply calling -release isn't
normally a guarantee of that.
My preferred approach is to have a -close or -invalidate method that
releases resources, breaks retain cycles, etc.. If -invalidate isn't
called before dealloc, that's OK, but I can also call -invalidate
explicitly if I know I want to tear down the object at a given time.
I think there are cases where the indefinite lifetime *is* what you
want, if you have objects that can lazily fault something in from
disk, or which encapsulate a sharable server connection, or etc. But
those objects should be the exception, so that you can be especially
aware of lifecycle issues in any code that deals with them. And even
so, I usually end up having to give them an -invalidate method
eventually, to deal with some odd situation.
I guess I do think of the delloc being called as a result of my
release -- and that seems to be the way it is working.
The approach I'm using now is to open the file in an init method, then
read a few 100 bytes of header in another method, then find pointers
to read other portions of the file and read some more data, then close
the file in the dealloc method. Lazy loading of data is an Objective -
C/Cocoa pattern.
The alternative would be to open the file, read the entire file, and
close it in the init method. I guess this is the approach used by NS
methods such as: initWithContentsOfFile, etc. However, the file could
be megabytes in size, and so this would be considerably slower.
Another alternative would be to not use a class but just use C
functions to do this, but that wouldn't be a Cocoa pattern at all.
Bottom line though, what are the consequences of leaving a file open?
When does it finally get closed?
Jim Merkel_______________________________________________
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