[Openmcl-devel] how does this work, exactly?

alex crain alexcrain at mail2.widgetworks.com
Thu Sep 30 05:42:32 PDT 2004


Maybe I'm just being dense, but I don't see how this answers my
question, which is: Regardless of how the MACPTR is handled,
in my example there is a lisp object that is only referenced by
a COCOA object and has no other presence in the lisp system.
I would expect it to be garbage collected because lisp doesn't
know about things internal to COCOA classes.

To modify your example:

(defparameter *big-list-of-all-windows* (make-objc-instance 
'ns:ns-array))

(defun make-window (&rest args)
   (let* ((w (apply 'make-instance 'some-lisp-subclass-of-an-objc-class 
args)))
       (send *big-list-of-all-windows* :add-object w)))

Make window creates a lisp instance and adds it to a cocoa array before 
the
local reference goes out of scope. How does lisp know not to GC my 
window
objects?


On Sep 29, 2004, at 10:46 PM, Gary Byers wrote:

>
>
> On Wed, 29 Sep 2004, alex crain wrote:
>
>>
>> I create some classes:
>>
>> (defclass tab-view-item (ns:ns-tab-view-item)
>> 	...
>> 	(:metaclass ns:+ns-object))
>>
>> (defclass tab-view (ns:ns-tab-view)
>> 	...
>> 	(:metaclass ns:+ns-object))
>>
>> And I create some instances...
>>
>> (send (make-instance 'tab-view)
>> 	 :add-tab-view-item (make-instance 'tab-view-item))
>>
>> I now have an instance of tab-view-item that is referenced by the
>> tab-view cocoa object but not, as far as I can tell, anywhere
>> in the lisp system. So, why doesn't lisp garbage collect my
>> tab-view-item?
>
> How does this work ?
>
> ? (#_malloc 20)
>
> On a foreign function call like this, two blocks of memory get 
> allocated:
>
> 1) a block of "foreign memory", at least 20 bytes long in this
>    example, in some area of memory managed by malloc
>
> 2) A lisp object of type MACPTR, which references (1).  Note that many
>    MACPTRs can reference the same address; MACPTRs that reference the
>    same address are EQL to each other, but not necessarily EQ.
>
> If the GC can prove that a lisp object of type MACPTR isn't referenced
> from any non-garbage lisp object, it can reclaim the memory used by
> that MACPTR (just as for conses, strings, functions,
> standard-instances, etc.)  That has nothing to do in general with
> whether or not any block of foreign memory that the MACPTR references
> remains allocated.
>
> A MACPTR to an ObjC instance tries to cache that fact; conceptually,
> it changes its class from MACPTR to the (foreign) class of the 
> instance.
>
> In general, an Objective C instance will remain allocated as long as
> its reference count is greater than 0.  It's tempting to say that
> whenever lisp code creates a MACPTR which referencs an ObjC intance
> it should increment that instance's reference count; whenever the GC
> discovers that such a MACPTR is about to become garbage, it should
> arrange to decrement the ObjC object's reference count.  This would
> help to prevent situations where a MACPTR has classified itself as
> an instance of some ObjC class but the instance in question has been
> deallocated.
>
> Unfortunately, I don't think that a scheme like that would scale well.
> (If it worked perfectly, foreign pointers that would otherwise be freed
> would linger until the GC could prove that there were no references
> to them, which might have adverse effects.
>
> I'd started to implement another (less ambitios) scheme, that involved
> "canonicalizing" the MACPTRs used to reference ObjC object (so that
> there was generally something more of a 1:1 correspondence.)  That
> scheme ran into other problems related to how pthread cleanup functions
> work in Darwin (threads become unable to respond to signals), and I
> backed out of that.
>
> I ultimately think that the "right" approach to this involves deeper
> integration of Lisp's GC and ObjC's memory management scheme (sneaking
> a GC-integrated zone_malloc implementation in there somewhere.)
>
> Unless/until something like this is done, ObjC instances aren't
> first-class lisp objects; this means that it's possible for "an 
> instance
> of foreign class X" to have its class changed to "freed, possibly no
> longer mapped chunk of memory", "total garbage", "instance of some
> other class entirely", etc. behind lisp's back.
>
> The fact that that scenario is -possible- doesn't mean that it's likely
> to occur; it's more likely to occur when dealing with ObjC objects 
> that're
> typically short-lived (NSEvents ...) than with objects that're 
> typically
> long-lived (NSWindows ...).
>
> Suppose that you had:
>
> (defparameter *big-list-of-all-windows* ())
>
> (defun make-window (&rest args)
>   (let* ((w (apply (make-instance 'some-window-class args))))
>     (push w *big-list-of-all-windows*)
>     w))
>
> (defun do-all-windows (f)
>    (dolist (w *big-list-of-all-windows*) (funcall f w)))
>
> That kind of code (as written) is a bad idea: if instances of
> SOME-WINDOW-CLASS are full-fledged, first-class lisp objects, they'd
> never get GC'ed as long as they were referenced from
> *BIG-LIST-OF-ALL-WINDOWS*, and you'd typically want to do something
> like:
>
> (defmethod window-close ((w some-window-class))
>   (setq *big-list-of-all-windows* (delete w *big-list-of-all-windows*))
>   (call-next-method))
>
> If "instances of SOME-WINDOW-CLASS" are not full-fledged and first-
> class, it'd be even more critical to avoid having references to them
> after they're closed.
>
> _______________________________________________
> Openmcl-devel mailing list
> Openmcl-devel at clozure.com
> http://clozure.com/mailman/listinfo/openmcl-devel
>




More information about the Openmcl-devel mailing list