[Openmcl-devel] Three questions
Gary Byers
gb at clozure.com
Sat Feb 9 02:56:55 PST 2008
On Fri, 8 Feb 2008, Ron Garret wrote:
> On Feb 8, 2008, at 10:50 PM, Gary Byers wrote:
>
>>
>>
>> On Fri, 8 Feb 2008, Andrew Shalit wrote:
>>
>>>
>>> On Feb 8, 2008, at 5:34 PM, R. Matthew Emerson wrote:
>>>
>>>>
>>>> On Feb 8, 2008, at 4:34 PM, Ron Garret wrote:
>>>>
>>>>> 1. Is there a way to tell when a window has been closed?
>>>>
>>>> I only know of the usual Cocoa/Objective-C ways:
>>>> * register to receive NSWindowWillCloseNotification
>>>> * implement windowWillClose: in the window's delegate
>>>
>>> This is a good example of the kind of thing that I think works better
>>> in MCL, which builds a clean Lisp layer on top of the native Mac OS
>>> libraries, rather than just providing a thin Lisp interface for
>>> directly programming the Mac OS libraries.
>>
>> I'd forgotten that there were no memory management problems with (or
>> limitations to) MCL's approach. Ah, truly that was a Golden Age ...
>
> LOL!
>
> Although it is certainly true that the Golden Age had its rough edges, it was
> (if memory serves) better than the current situation where, if one tries to
> operate on a retained handle to an NSWindow that the user has closed, CCL
> dumps core. (I don't mean to rag on CCL here. From what I can tell, this is
> a Cocoa issue. I haven't actually tried it, but I see no reason to believe
> that an Objective C program would behave any differently. But what do I
> know?)
>
> rg
>
My interpretation of that is that it's a general memory management issue:
if you close an NSWindow and that causes the NSWindow to be released
(it doesn't do so necessarily: for windows that don't have associated
NWindowControllers and don't have associated NSDocuments: see
#/setReleasedWhenClosed:) then you wind up with your hands on
something presented as a (more-or-less) first-class CLOS object
that's just had some foreign "deallocation" process applied to
it (and may have had a "reallocation" process applied to it.).
If the lisp GC scribbles over some object that we can reference,
we'd call that a GC bug; I prefer to call this "unimplemented
integration between the lisp and ObjC memory management systems".
Whatever you'd call it, the results are often unpleasant; it
isn't lisp-like to say that an object that we can reference
"got deallocated", and that generally has no meaning. (Lisp
objects that we -can't- reference get deallocated all the time,
modulo GC bugs.)
? (defvar *w* (gui::new-cocoa-window :closable t))
*W*
? (#/setReleasedWhenClosed: *w* nil)
NIL
? (#/close *w*)
NIL
? *w*
#<NS-WINDOW <NSWindow: 0x1882e490> (#x1882E490)>
? (#/isVisible *w*)
NIL
Since we asked that *w* not be released when it was closed, it's
still a valid object (and in fact, it's still a valid NSWindow):
? (#/orderFront: *w* +null-ptr+)
NIL
? (#/setTitle: *w* #@"Lazarus")
NIL
Hmm. Closing a window doesn't necessarily have anything to do with
releasing it (decrementing its "retain count" and possibly
deallocating it.)
Let's close *w* and release it. First, just to humor me, let's
use CCL::%INC-PTR to return a copy of *W*:
? (%inc-ptr *w* 0)
#<NS-WINDOW <NSWindow: 0x1882e490> (#x1882E490)>
Another pointer that points to the same address (#x1882E490) as *w*
is also recognized as the same NSWindow.
? (#/close *w*)
NIL
? (#/release *w*)
NIL
Now, we're sort of back to your original question, which could
be rephrased as "is there a way of telling when some NSObject
has been deallocated, given that we have to - at least occasionally -
be aware of that possibility ?
As you noted, after *w* has been released:
? (type-of *w*)
NS:NS-WINDOW
which is wrong. Determining the type of a MACPTR (actually
trying to determine the type of the address it encapsulates) is
heuristic and a bit expensive, so the foreign type info is
cached inside the MACPTR object itself. We could say (through
some easily-implented primitive that I don't believe is actually
implemented) "clear that cached foreign type info, and try again
to determine the type of *w*"; we could also see what happens
if we try to determine the type of some other pointer that
points the same place (encapsulates the same address) as *w*
? (type-of (%inc-ptr *w* 0))
MACPTR
If *w* is pointing to a block of freed memory, that seems like
the most reasonable answer. If it's reallocated as some other
type of NSObject, we might get a different answer. If it's
reallocated as another NSWindow, you may have to resort
to other means to determine that it's not Good Old *W* (aka
The NSWindow That Couldn't Die.)
Speaking of The Undead: one traditional OSX debugging technique which
is used for both Cocoa and Core Foundation programming is to enable
"Zombie" objects: when something would otherwise be deallocated, it
instead has its class changed to a special NSZombie class (or the CF
equivalent.) Instances of NSZombie respond to most messages by
logging the fact that a message was sent to a zombie (and would
otherwise have been sent to a freed object). (Of course,
#/riseFromGraveAndTerrifySuperstitiousNatives is directly implemented...)
Anyway ... is it a good thing that people doing Cocoa programming in
CCL have to occasionally be aware of this sort of thing ? Of course
not. I think that we all agree that this sort of thing shouldn't be
exposed to the user but there are differences of opinion about how
that should best be achieved. I doubt that anyone would disagree that
better-integrating ObjC and Lisp memory management would be a Good
Thing (that would incidentally make this problem go away, to be
replaced with the "why is this guy holding on to NSWindow objects -
keeping them from being GCed - so long?" problem). I have difficulty
reaching the conclusion that the fact that this integration doesn't
exist somehow makes MCL-like encapsulation a good idea; there seems to
be too much evidence to the contrary.
More information about the Openmcl-devel
mailing list