From: Fredrik T. <fr...@do...> - 2012-09-29 07:12:42
|
Dear list, Would it be possible to create a class in such a fashion that it could be GC'd once all its instances are gone? I've tried creating a class in a couple of ways that I thought would work, and then installing a finalizer function on it to show if it were GC'd, but I can't seem to get them to be GC'd whatever I do, even if I hack away all the references I've been able to find, including the following obviously ugly ways: (let ((test-class (defclass foo (transient) ()))) (finalize test-class #'(lambda () (print "foo"))) (setf (sb-kernel:classoid-cell-pcl-class (sb-kernel:find-classoid-cell 'foo)) nil) (sb-mop:remove-direct-subclass (find-class 'transient) test-class)) (let ((test-class (make-instance 'standard-class :name 'bar :direct-superclasses (list (find-class 'transient))))) (finalize test-class #'(lambda () (print "bar"))) (assert (null (ignore-errors (find-class 'bar)))) (sb-mop:remove-direct-subclass (find-class 'transient) test-class)) I then run (gc :full t), but get printed neither "foo" nor "bar". Is it *at all* possible to create classes that can be GC'd, and if it is, can it be done in a way that is not a horribly ugly hack? (Even better, can it be done in any way that might even work outisde SBCL?) -- Fredrik Tolf |
From: Christophe R. <cs...@ca...> - 2012-09-29 08:40:16
|
Fredrik Tolf <fr...@do...> writes: > I've tried creating a class in a couple of ways that I thought would work, > and then installing a finalizer function on it to show if it were GC'd, > but I can't seem to get them to be GC'd whatever I do, even if I hack away > all the references I've been able to find, including the following > obviously ugly ways: > > (let ((test-class (defclass foo (transient) ()))) > (finalize test-class #'(lambda () (print "foo"))) > (setf (sb-kernel:classoid-cell-pcl-class (sb-kernel:find-classoid-cell 'foo)) nil) > (sb-mop:remove-direct-subclass (find-class 'transient) test-class)) Well, this seems to be nearly there: if I run (let ((c (let ((test-class (defclass foo (transient) ()))) (finalize test-class #'(lambda () (print "foo"))) (setf (sb-kernel:classoid-cell-pcl-class (sb-kernel:find-classoid-cell 'foo)) nil) (sb-mop:remove-direct-subclass (find-class 'transient) test-class)))) (dotimes (i 3) (gc :full t)) (sb-vm::map-referencing-objects #'print :dynamic c)) then I get as output #<SB-KERNEL:STANDARD-CLASSOID FOO> (#<STANDARD-CLASS FOO> (24 . #<CLOSURE # {100295C189}>)) The first of these is obvious, I guess: we'd need an extra (setf (sb-kernel:classoid-pcl-class (sb-kernel:find-classoid 'foo)) nil) to remove the reference from the classoid (which raises the question of why the classoid and the classoid-cell both need a reference... The second is more problematic; I couldn't convince myself that it came from a real reference, and MAP-REFERENCING-OBJECTS isn't reliable enough to do a fine dissection (adding the clearing of CLASSOID-PCL-CLASS made the other printed reference go away). On the other hand, I wasn't getting the finalization message printed either, so more investigation is needed. Cheers, Christophe |
From: Fredrik T. <fr...@do...> - 2012-09-29 16:09:52
|
On Sat, 29 Sep 2012, Christophe Rhodes wrote: > sb-vm::map-referencing-objects I didn't know of that function. That's quite a useful debugging tool. Thanks! :) > The second is more problematic; I couldn't convince myself that it came > from a real reference Indeed; it makes me wonder if the compiler or some other even more basic part of SBCL keeps some kind of special reference to it, and makes me wonder if it's even possible to GC classes, and I'm not really competent enough in SBCL's internal to answer that question myself. -- Fredrik Tolf |
From: Nikodemus S. <nik...@ra...> - 2012-09-30 11:29:24
|
On 29 September 2012 19:09, Fredrik Tolf <fr...@do...> wrote: > On Sat, 29 Sep 2012, Christophe Rhodes wrote: >> sb-vm::map-referencing-objects A caveat: it doesn't inspect closures or funcallable instances. When someone has a moment, re-building it on top of SB-INTROSPECT:MAP-ROOT would be good. > Indeed; it makes me wonder if the compiler or some other even more basic > part of SBCL keeps some kind of special reference to it, and makes me > wonder if it's even possible to GC classes, and I'm not really competent > enough in SBCL's internal to answer that question myself. It should be possible, but it's a bit of a pain right now. Eg. if you've called methods, their dispatch tables are going to hold references to the class wrapper. Cheers, -- Nikodemus |
From: Fredrik T. <fr...@do...> - 2012-09-30 18:12:53
|
On Sun, 30 Sep 2012, Nikodemus Siivola wrote: > On 29 September 2012 19:09, Fredrik Tolf <fr...@do...> wrote: >> Indeed; it makes me wonder if the compiler or some other even more basic >> part of SBCL keeps some kind of special reference to it, and makes me >> wonder if it's even possible to GC classes, and I'm not really competent >> enough in SBCL's internal to answer that question myself. > > It should be possible, but it's a bit of a pain right now. Eg. if > you've called methods, their dispatch tables are going to hold > references to the class wrapper. Oh, I see; that seems like quite a bit of pain, indeed. If I propose, then, such transient classes as a feature request instead, would that be taken seriously? :) -- Fredrik Tolf |
From: Nikodemus S. <nik...@ra...> - 2012-09-30 19:40:45
|
On 30 September 2012 21:09, Fredrik Tolf <fr...@do...> wrote: >> It should be possible, but it's a bit of a pain right now. Eg. if >> you've called methods, their dispatch tables are going to hold >> references to the class wrapper. I take this back, actually. It seems I misremembered: wrappers point to classes only though classoids, so nuking references to classes in classoids should be enough to take care of them. Old wrappers left over should be harmless and will be dropped from the caches on their own. There might be another surprise someone inside PCL, but nothing overly exciting, I think. Cheers, -- Nikodemus |
From: Fredrik T. <fr...@do...> - 2012-10-01 23:45:49
|
On Sun, 30 Sep 2012, Nikodemus Siivola wrote: >>> It should be possible, but it's a bit of a pain right now. Eg. if >>> you've called methods, their dispatch tables are going to hold >>> references to the class wrapper. > > I take this back, actually. It seems I misremembered: wrappers point > to classes only though classoids, so nuking references to classes in > classoids should be enough to take care of them. Old wrappers left > over should be harmless and will be dropped from the caches on their > own. > > There might be another surprise someone inside PCL, but nothing overly > exciting, I think. In that case, it remains a good question why I can't get classes GC'd at all, though. :-) -- Fredrik Tolf |