> A quick test (on Mono) says "no", but trying with a class that > declares __del__ doesn't either, so I'd want to hook up a debugger on > Windows to check for sure. I'm not sure if the backing types created > by IronPython have finalizers, but I think not (and reading through > the RefEmit code will take longer than I have right now.)
Sounds like IronPython would not support __del__ at all. Is this a basic, maybe well-known issue or are finalizers principally supported, but currently broken? I appended a unit test file and would like to know which of the tests exactly fail on IronPython. I will surely take the time to test this myself, but it might take some days until I come to setting up mono and IronPython. And I thought you might be interested in these tests too ;-) To support acquired finalizers, Jython would have to track all instances for each class. So it could update them if the class would acquire a finalizer. Obviously this is insanely expensive for such a rare use-case, so I added a builtin method __ensure_finalizer__ to Jython, which allows - at least manually - to fix this. One can tell already existing instances manually that their class acquired a finalizer (also works for new style classes): class A(): pass def A__del__(): print "A finalized" a1 = A() A.__del__ = A__del__ a1.__ensure_finalizer__() a1 = None I have only rough knowledge of .net, but believe it behaves somewhat equal to Java regarding to gc and finalizers. Since IronPython appears to have equal issues, I would offer guidance and discussion if you might want to port the Jython approach. At least I wanted to make you aware of the __ensure_finalizer__()-method-manual-fix-approach and suggest that if IronPython would ever implement an equal method to agree on a common name for it. > IronPython is about the same: > https://github.com/IronLanguages/main/blob/ipy-2.7-maint/Languages/IronPython/IronPython.Modules/gc.cs Okay, I already expected something like this. I have rough plans to enhance the Jython gc module by a manual track-method. For debugging one can add certain objects to it via gc.track(object). Then gc would monitor these and serve the original gc module methods with this information (e.g. number of collected (i.e. monitored and collected) objects). I just wanted to make you aware of this and suggest that if you might want to do an equal monitoring, to agree on a common name for the manual track method too. However, I would resume this topic when I proceed with this. - Stefan > Gesendet: Donnerstag, 18. September 2014 um 14:35 Uhr > Von: "Jeff Hardy" <jdha...@gmail.com> > An: "Stefan Richthofer" <stefan.richtho...@gmx.de> > Cc: "ironpython-users@python.org" <ironpython-users@python.org>, "Dino > Viehland" <di...@microsoft.com> > Betreff: Re: [Ironpython-users] Some questions about gc and finalizers > > (+dinov, who just needs to page this in rather than learn it all from scratch) > > On Wed, Sep 17, 2014 at 2:18 PM, Stefan Richthofer > <stefan.richtho...@gmx.de> wrote: > > Dear IronPython community, > > > > I recently worked on Jython issue 1057 (http://bugs.jython.org/issue1057) > > and also improved the current solution of > > http://bugs.jython.org/issue1634167 a bit. For these issues, it is very > > hard for Jython to emulate CPython behavior due to the fundamentally > > different GC implementation, so I suspected, IronPython might have similar > > problems and wondered how they are solved here. > > Since I never used IronPython or .net, I would appreciate answers on a > > rather abstract level and apologize that I have no ambition to look into > > the source myself. I'm just hoping to find someone (optimally a core-dev), > > who can simply answer it and is maybe open for a discussion of solutions. > > > > My questions are: > > - does IronPython support acquired finalizers? > > i.e. > > class A(): > > pass > > > > def A__del__(): > > print "A finalized" > > > > a1 = A() > > A.__del__ = A__del__ > > a1 = None > > > > > > Would it output "A finalized" or not? > > A quick test (on Mono) says "no", but trying with a class that > declares __del__ doesn't either, so I'd want to hook up a debugger on > Windows to check for sure. I'm not sure if the backing types created > by IronPython have finalizers, but I think not (and reading through > the RefEmit code will take longer than I have right now.) > > > In Jython this won't work so easy, because Jython avoids to overwrite the > > finalize method for all instances for its expensiveness. So only instances > > known to need finalization on creation time will be finalized. AfaIk, > > finalizers in .net are as expensive as in Java, so how would this work in > > IronPython? > > > > > > - how complete is the support of the gc module? > > i.e. > > In Jython the support is rather poor; most methods are just implemented as > > stubs, i.e. one-liners as > > throw Py.NotImplementedError("not applicable to Java GC") > > > > IronPython is about the same: > https://github.com/IronLanguages/main/blob/ipy-2.7-maint/Languages/IronPython/IronPython.Modules/gc.cs > > > gc.collect usually returns the number of collected objects, but Jython just > > calls java.lang.System.gc() and returns None. I believe, tracking the > > number of collected objects would be possible, but very expensive, so this > > maybe could be added as a start-up-flag feature for debugging. How far does > > IronPython support this currently? > > IronPython just returns the number of bytes freed by the call: > https://github.com/IronLanguages/main/blob/ipy-2.7-maint/Languages/IronPython/IronPython/Runtime/PythonContext.cs#L3465. > > - Jeff >
''' Created on 06.08.2014 ''' import unittest import types import time import gc finalizeMsgList = [] verbose = False resurrectedObject_I = None resurrectedObject_J = None resurrectedObject_K = None resurrectedObject_L = None resurrectedObject_M = None resurrectedObject_N = None def runGC(): gc.collect() #The sleep time is for Python implementations that run gc in a parallel thread (e.g. Jython) time.sleep(0.1) class ResurrectableDummyClass(): def __init__(self, name): self.name = name self.doResurrection = True def __str__(self): return self.name class ResurrectableDummyClassNew(object): def __init__(self, name): self.name = name self.doResurrection = True def __str__(self): return self.name def __del__I(self): global resurrectedObject_I global finalizeMsgList if finalizeMsgList is None: finalizeMsgList = [] finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_I = self def __del__J(self): global resurrectedObject_J finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_J = self def __del__K(self): global resurrectedObject_K finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_K = self def __del__L(self): global resurrectedObject_L global finalizeMsgList if finalizeMsgList is None: finalizeMsgList = [] finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_L = self def __del__M(self): global resurrectedObject_M finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_M = self def __del__N(self): global resurrectedObject_N finalizeMsgList.append(str(self)+" finalized (ResurrectableDummyClass)") if verbose: print str(self)+" finalized (ResurrectableDummyClass)" if self.doResurrection: resurrectedObject_N = self delI = __del__I delJ = __del__J delK = __del__K delL = __del__L delM = __del__M delN = __del__N class DummyClass(): def __init__(self, name): self.name = name def __str__(self): return self.name class DummyClassDel(): def __init__(self, name): self.name = name def __str__(self): return self.name def __del__(self): finalizeMsgList.append(str(self)+" finalized (DummyClassDel)") if verbose: print str(self)+" finalized (DummyClassDel)" class DummyClassNew(object): def __init__(self, name): self.name = name def __str__(self): return self.name class DummyClassDelNew(object): def __init__(self, name): self.name = name def __str__(self): return self.name def __del__(self): finalizeMsgList.append(str(self)+" finalized (DummyClassDelNew)") if verbose: print str(self)+" finalized (DummyClassDelNew)" class DummyFileClassNew(file): def __init__(self, name): self.name0 = name def __str__(self): return self.name0 def __del__(self): finalizeMsgList.append(str(self)+" finalized (DummyFileClassNew)") if verbose: print str(self)+" finalized (DummyFileClassNew)" def __del__class(self): finalizeMsgList.append(str(self)+" finalized (acquired by class)") if verbose: print str(self)+" finalized (acquired by class)" def __del__object(self): finalizeMsgList.append(str(self)+" finalized (acquired by object)") if verbose: print str(self)+" finalized (acquired by object)" def __del__object0(): finalizeMsgList.append("_ finalized (acquired by object)") if verbose: print "_ finalized (acquired by object)" delClass = __del__class delObject = __del__object delObject0 = __del__object0 class TestFinalizers(unittest.TestCase): def test_finalizer_builtin_oldStyleClass(self): A = DummyClassDel("A") A = None runGC() self.assertIn("A finalized (DummyClassDel)", finalizeMsgList) def test_classAcquiresFinalizer_beforeInstanciation_oldStyleClass(self): DummyClass.__del__ = delClass B = DummyClass("B") B = None runGC() self.assertIn("B finalized (acquired by class)", finalizeMsgList) del DummyClass.__del__ def test_classAcquiresFinalizer_afterInstanciation_oldStyleClass(self): #okay to fail in Jython without the manual ensureFinalizer call C = DummyClass("C") DummyClass.__del__ = delClass try: C.__ensure_finalizer__() except: pass C = None runGC() self.assertIn("C finalized (acquired by class)", finalizeMsgList) del DummyClass.__del__ def test_instanceAcquiresFinalizer_bound_oldStyleClass(self): D = DummyClassDel("D") dl = types.MethodType(delObject, D.name) D.__del__ = dl D = None runGC() self.assertNotIn("D finalized (DummyClassDel)", finalizeMsgList) self.assertIn("D finalized (acquired by object)", finalizeMsgList) def test_finalizer_builtin_newStyleClass(self): E = DummyClassDelNew("E") E = None runGC() self.assertIn("E finalized (DummyClassDelNew)", finalizeMsgList) def test_classAcquiresFinalizer_beforeInstanciation_newStyleClass(self): DummyClassNew.__del__ = delClass F = DummyClassNew("F") F = None runGC() self.assertIn("F finalized (acquired by class)", finalizeMsgList) del DummyClassNew.__del__ def test_classAcquiresFinalizer_afterInstanciation_newStyleClass(self): #okay to fail in Jython without the manual __ensure_finalizer__ call G = DummyClassNew("G") DummyClassNew.__del__ = delClass try: G.__ensure_finalizer__() except: pass G = None runGC() self.assertIn("G finalized (acquired by class)", finalizeMsgList) del DummyClassNew.__del__ def test_instanceAcquiresFinalizer_bound_newStyleClass(self): """ It seems, CPython prohibits new style instances from acquiring a finalizer. """ H = DummyClassDelNew("H") H.__del__ = types.MethodType(delObject, H.name) H = None runGC() self.assertIn("H finalized (DummyClassDelNew)", finalizeMsgList) self.assertNotIn("H finalized (acquired by object)", finalizeMsgList) def test_instanceAcquiresFinalizer_bound_newStyleClass2(self): """ It seems, CPython prohibits new style instances from acquiring a finalizer. If one calls the instance-acquired __del__ manually, it works, but the gc will still call the old one. """ H = DummyClassDelNew("H2") H.__del__ = types.MethodType(delObject, H.name) H.__del__() H = None runGC() self.assertIn("H2 finalized (DummyClassDelNew)", finalizeMsgList) self.assertIn("H2 finalized (acquired by object)", finalizeMsgList) def test_objectResurrection_oldStyleClass(self): ResurrectableDummyClass.__del__ = delI I = ResurrectableDummyClass("I") I = None runGC() self.assertIn("I finalized (ResurrectableDummyClass)", finalizeMsgList) self.assertEqual(str(resurrectedObject_I), "I") def test_objectDoubleResurrection_oldStyleClass(self): #okay to fail in Jython without the manual ensureFinalizer calls ResurrectableDummyClass.__del__ = delJ J = ResurrectableDummyClass("J") J = None runGC() self.assertIn("J finalized (ResurrectableDummyClass)", finalizeMsgList) global resurrectedObject_J self.assertEqual(str(resurrectedObject_J), "J") J = resurrectedObject_J resurrectedObject_J = None self.assertIsNone(resurrectedObject_J) try: #For Jython one can restore the finalizer manually. #This is offered as an easy fix if the CPython behavior #in this test should be needed for some reason. J.__ensure_finalizer__() except: pass J = None runGC() self.assertEqual(str(resurrectedObject_J), "J") resurrectedObject_J.doResurrection = False try: #again... resurrectedObject_J.__ensure_finalizer__() except: pass resurrectedObject_J = None runGC() self.assertIsNone(resurrectedObject_J) def test_objectDoubleResurrectionAndFinalize_oldStyleClass(self): #okay to fail in Jython without the manual ensureFinalizer calls ResurrectableDummyClass.__del__ = delK K = ResurrectableDummyClass("K") K = None runGC() self.assertIn("K finalized (ResurrectableDummyClass)", finalizeMsgList) finalizeMsgList.remove("K finalized (ResurrectableDummyClass)") self.assertNotIn("K finalized (ResurrectableDummyClass)", finalizeMsgList) global resurrectedObject_K self.assertEqual(str(resurrectedObject_K), "K") K = resurrectedObject_K resurrectedObject_K = None self.assertIsNone(resurrectedObject_K) try: K.__ensure_finalizer__() except: pass K = None runGC() self.assertIn("K finalized (ResurrectableDummyClass)", finalizeMsgList) self.assertEqual(str(resurrectedObject_K), "K") def test_objectResurrection_newStyleClass(self): ResurrectableDummyClassNew.__del__ = delL L = ResurrectableDummyClassNew("L") L = None runGC() self.assertIn("L finalized (ResurrectableDummyClass)", finalizeMsgList) self.assertEqual(str(resurrectedObject_L), "L") def test_objectDoubleResurrection_newStyleClass(self): #okay to fail in Jython without the manual ensureFinalizer calls ResurrectableDummyClassNew.__del__ = delM M = ResurrectableDummyClassNew("M") M = None runGC() self.assertIn("M finalized (ResurrectableDummyClass)", finalizeMsgList) global resurrectedObject_M self.assertEqual(str(resurrectedObject_M), "M") M = resurrectedObject_M resurrectedObject_M = None self.assertIsNone(resurrectedObject_M, None) try: M.__ensure_finalizer__() except: pass M = None runGC() self.assertEqual(str(resurrectedObject_M), "M") def test_objectDoubleResurrectionAndFinalize_newStyleClass(self): #okay to fail in Jython without the manual ensureFinalizer calls ResurrectableDummyClassNew.__del__ = delN N = ResurrectableDummyClassNew("N") N = None runGC() self.assertIn("N finalized (ResurrectableDummyClass)", finalizeMsgList) finalizeMsgList.remove("N finalized (ResurrectableDummyClass)") self.assertNotIn("N finalized (ResurrectableDummyClass)", finalizeMsgList) global resurrectedObject_N self.assertEqual(str(resurrectedObject_N), "N") N = resurrectedObject_N resurrectedObject_N = None self.assertIsNone(resurrectedObject_N) try: N.__ensure_finalizer__() except: pass N = None runGC() self.assertIn("N finalized (ResurrectableDummyClass)", finalizeMsgList) self.assertEqual(str(resurrectedObject_N), "N") def test_file_overwrite_del(self): O = DummyFileClassNew("O") O = None runGC() self.assertIn("O finalized (DummyFileClassNew)", finalizeMsgList) if __name__ == '__main__': unittest.main()
_______________________________________________ Ironpython-users mailing list Ironpython-users@python.org https://mail.python.org/mailman/listinfo/ironpython-users