Squeak SmalltalkJoker Squeak Smalltalk : System : prevnext Finalization Garbage Collection

Hi,
The thing to keep in mind for all of the places where finalization is
provided in the image is that finalization is ALMOST NEVER a
replacement for proper resource management. In short: The only reason
why we provide finalization support for some objects (such as files
and sockets) is that without them, any "forgotten" file/socket would
leave to dangling OS resources and therefore get problematic before
too long. As with all resource-containing objects, having proper
resource-deallocation is critical as well as application dependent.
The only thing the system can do in general is to make sure that it
closes the appropriate resources when it can prove that this object is
no longer used (e.g., GCed). Finalization is sometimes understood to
be "sort of" resource management but in almost all "real world
applications" this won't work too well.
Therefore, if you write an app which uses resource-allocating objects,
it is YOUR task to make sure they are closed properly. Which is one of
the reasons why patterns such as:
    file := self openFile: 'foo.txt'
    [self doSomethingWith: file] ensure:[file close].
are used. IOW, the above ensures that the opened file is indeed
properly closed after we are finished with it, finalization or not.
(completely OT, but I have long thought that it might be wiser not to
provide the current finalization facilities as they typically lead to
worse code since people are relying on it as the default rather than
the exceptional facility that it actually constitutes)
> If I have an object aNode that holds onto aSocket then
> I can do all sorts of things with the socket.  If I forget about
> aNode, say because it was in an inspector, the socket is still
> around and survives any number of GCs.  I think this is because
> it is registered externally?
No. It is because finalization is only run if the object is GCed and
your inspector will hold a live reference to aNode and aNode will hold
a live reference to the socket and so the socket doesn't get GCed.
(note that the " chase pointers" feature can be misleading as it is
assumed that for this feature you are interested in "all but" the
reference paths starting from the inspector you hold).
> If I wanted the semantics that after dropping aNode
> I wanted to send closeAndDestroy to its socket I feel
> I might want to head in the area of finalisation but
> I don't know how to do this.
This depends on what you consider "dropping" aNode. If you mean "wait
until it is GCed" rather than somehow explicitly "shut down", then you
_may_ want to use finalization. If so, have a look at
Object>>toFinalizeSend:to:with:.
> What is the best, or considered, way to handle processes
> in objects when you then forget about the object without
> cleaning up the process.  If you have a process blocking
> on a semaphore I assume that it will never be GCd because,
> at least, the scheduler has got a hold of it.  So should I
> also be looking at finalisation here?
It depends. A process blocking on a semaphore WILL get GCed if the
associated semaphore gets GCed. For example:
| process sema weakObserver |
sema := Semaphore new.
process := [sema wait] forkAt: Processor userInterruptPriority.
weakObserver := WeakArray with: process.
"No GC both semaphore and process"
process := sema := nil.
Smalltalk garbageCollect.
"lo and behold! it's gone"
weakObserver first.
So if you'd have a process blocking on a semaphore in a socket, all of
socket, semaphore and process are likely to "go away" at the same time.
Cheers,
  - Andreas