|
From: Ype K. <yk...@xs...> - 2001-12-17 19:36:16
|
Dear jythoneers,
This is a rather involved bug, so I hope it is JVM dependent.
It shows up in rather unusual circumstances.
Showing the bug involves running the tstdel.py file
from the command line. This program execfile()'s
the modules tstdel1.py and tstdel2.py
which differ only slightly.
All three program files are included in this post, see below.
The tstdel.py program gives the output shown below.
Each output line mentioning an object is printed
from a constructor ('Hello' and 'Hello2') or
from a __del__(self) method ('Goodbye' and Goodbye2')
in the execfile()'d programs.
The output indicates that when using an object of
class executor the deltest2 object is correctly gc()'d.
However when an object of class clearingExecutor is
used the deltest2 object is not gc()'d, even after
the clearingExecutor is del'ed:
(jython 21b1, java 1.1.8, OS2)
<output from tstdel.py>
__main__.executor
Hello <<unknown>.deltest1 instance at 390229>
Hello2 <<unknown>.deltest2 instance at 296443>
after del __main__.executor
Goodbye <<unknown>.deltest1 instance at 390229>
Goodbye2 <<unknown>.deltest2 instance at 296443>
__main__.clearingExecutor
Hello <<unknown>.deltest1 instance at 298665>
Goodbye <<unknown>.deltest1 instance at 298665>
Hello2 <<unknown>.deltest2 instance at 293293>
after del __main__.clearingExecutor
<end of output from tstdel.py>
Before the executor object is del'ed it references
a deltest1 and a deltest2 object, and after the executor object
is del'ed both the deltest1 object and the deltest2 object
are __del__()'d. This is expected, and it might exclude the
possibility of dangling references from java classes created
to perform execfile().
The clearingExecutor correctly clears the deltest1 instance
from its self.glb, as is seen in the Goodbye from the deltest1
instance at 298665, which is output before the next Hello2.
The bug:
Even before deleting the clearningExecutor
I would expect a Goodbye2 from the
deltest2 instance at 293293.
But this deltest2 instance is not __del__()'ed,
not even after del'ing the clearingExecutor object.
There seems to be a dangling reference
to the deltest2 object at 293293.
<The main program tstdel.py:>
from java.lang.System import gc, runFinalization
from time import sleep
class executor:
def __init__(self):
self.glb = {}
def exf(self, fnam):
execfile(fnam, self.glb, self.glb)
class clearingExecutor:
def __init__(self):
self.glb = {}
def exf(self, fnam):
execfile(fnam, self.glb, self.glb)
self.glb.clear()
def cleanUp():
gc()
runFinalization()
sleep(2)
x = executor()
y = clearingExecutor()
print x.__class__
x.exf('tstdel1.py')
cleanUp()
x.exf('tstdel2.py')
cleanUp()
print 'after del', x.__class__
del x
cleanUp()
print ''
print y.__class__
y.exf('tstdel1.py')
cleanUp()
y.exf('tstdel2.py')
cleanUp()
print 'after del', y.__class__
del y
cleanUp()
cleanUp()
<end of tstdel.py>
<The tstdel1.py program:>
import java
println = java.lang.System.out.println
class deltest1:
def __init__(self):
self.println = java.lang.System.out.println
self.println('Hello ' + repr(self))
def __del__(self):
self.println('Goodbye ' + repr(self))
td1 = deltest1()
<end of tstdel1.py>
The tstdel2.py program:
import java
println = java.lang.System.out.println
class deltest2:
def __init__(self):
self.println = java.lang.System.out.println
self.println('Hello2 ' + repr(self))
def __del__(self):
println('Goodbye2 ' + repr(self))
td2 = deltest2()
<end of tstdel2.py program>
The only difference (apart from names) between tstdel1.py and tstdel2.py
is in the __del__() method. Class deltest2 references a
function in module scope to provide its output, class deltest1
uses the same function but as one of its attributes.
This difference seems to cause a deltest2 object to never become
garbage when the dictionary against which tstdel2.py is executed
is clear()'d.
It is possible that this bug is related to the 'NameError: tracer'
I posted earlier (I gave up to isolate this possible bug).
If/when these two are related a possible explanation would be
that in some execution frame there is a wrong reference to an
earlier frame. This could in this case form a dangling reference
and in the 'NameError: tracer' case cause a deletion from the
wrong namespace.
Again, I do hope that this one is platform dependent.
If not, I'll gladly report a bug on sourceforge...
Have fun,
Ype
P.S. 21b1 is otherwise working very well for me.
|
|
From: Samuele P. <ped...@bl...> - 2001-12-17 20:37:08
|
Hi,
use
print 'Goodbye2 ' + repr(self)
instead of
println('Goodbye2 ' + repr(self))
and retry <wink>.
PS: the explanation is left as an exercise to the
reader :)
----- Original Message -----
From: Ype Kingma <yk...@xs...>
To: <jyt...@li...>
Sent: Monday, December 17, 2001 8:45 PM
Subject: [Jython-dev] Python object not gc()'d, 21b1
> Dear jythoneers,
>
> This is a rather involved bug, so I hope it is JVM dependent.
> It shows up in rather unusual circumstances.
>
> Showing the bug involves running the tstdel.py file
> from the command line. This program execfile()'s
> the modules tstdel1.py and tstdel2.py
> which differ only slightly.
> All three program files are included in this post, see below.
>
> The tstdel.py program gives the output shown below.
> Each output line mentioning an object is printed
> from a constructor ('Hello' and 'Hello2') or
> from a __del__(self) method ('Goodbye' and Goodbye2')
> in the execfile()'d programs.
>
> The output indicates that when using an object of
> class executor the deltest2 object is correctly gc()'d.
> However when an object of class clearingExecutor is
> used the deltest2 object is not gc()'d, even after
> the clearingExecutor is del'ed:
> (jython 21b1, java 1.1.8, OS2)
>
> <output from tstdel.py>
>
> __main__.executor
> Hello <<unknown>.deltest1 instance at 390229>
> Hello2 <<unknown>.deltest2 instance at 296443>
> after del __main__.executor
> Goodbye <<unknown>.deltest1 instance at 390229>
> Goodbye2 <<unknown>.deltest2 instance at 296443>
>
> __main__.clearingExecutor
> Hello <<unknown>.deltest1 instance at 298665>
> Goodbye <<unknown>.deltest1 instance at 298665>
> Hello2 <<unknown>.deltest2 instance at 293293>
> after del __main__.clearingExecutor
>
> <end of output from tstdel.py>
>
> Before the executor object is del'ed it references
> a deltest1 and a deltest2 object, and after the executor object
> is del'ed both the deltest1 object and the deltest2 object
> are __del__()'d. This is expected, and it might exclude the
> possibility of dangling references from java classes created
> to perform execfile().
>
> The clearingExecutor correctly clears the deltest1 instance
> from its self.glb, as is seen in the Goodbye from the deltest1
> instance at 298665, which is output before the next Hello2.
>
> The bug:
> Even before deleting the clearningExecutor
> I would expect a Goodbye2 from the
> deltest2 instance at 293293.
> But this deltest2 instance is not __del__()'ed,
> not even after del'ing the clearingExecutor object.
> There seems to be a dangling reference
> to the deltest2 object at 293293.
>
>
> <The main program tstdel.py:>
>
> from java.lang.System import gc, runFinalization
> from time import sleep
>
> class executor:
> def __init__(self):
> self.glb = {}
>
> def exf(self, fnam):
> execfile(fnam, self.glb, self.glb)
>
>
> class clearingExecutor:
> def __init__(self):
> self.glb = {}
>
> def exf(self, fnam):
> execfile(fnam, self.glb, self.glb)
> self.glb.clear()
>
>
> def cleanUp():
> gc()
> runFinalization()
> sleep(2)
>
>
> x = executor()
> y = clearingExecutor()
>
> print x.__class__
>
> x.exf('tstdel1.py')
> cleanUp()
>
> x.exf('tstdel2.py')
> cleanUp()
>
> print 'after del', x.__class__
> del x
>
> cleanUp()
>
> print ''
> print y.__class__
>
> y.exf('tstdel1.py')
> cleanUp()
>
> y.exf('tstdel2.py')
> cleanUp()
>
> print 'after del', y.__class__
> del y
>
> cleanUp()
>
> cleanUp()
>
>
> <end of tstdel.py>
>
> <The tstdel1.py program:>
>
> import java
> println = java.lang.System.out.println
>
> class deltest1:
> def __init__(self):
> self.println = java.lang.System.out.println
> self.println('Hello ' + repr(self))
>
> def __del__(self):
> self.println('Goodbye ' + repr(self))
>
> td1 = deltest1()
>
> <end of tstdel1.py>
>
> The tstdel2.py program:
>
> import java
> println = java.lang.System.out.println
>
> class deltest2:
> def __init__(self):
> self.println = java.lang.System.out.println
> self.println('Hello2 ' + repr(self))
>
> def __del__(self):
> println('Goodbye2 ' + repr(self))
>
> td2 = deltest2()
>
> <end of tstdel2.py program>
>
> The only difference (apart from names) between tstdel1.py and tstdel2.py
> is in the __del__() method. Class deltest2 references a
> function in module scope to provide its output, class deltest1
> uses the same function but as one of its attributes.
>
> This difference seems to cause a deltest2 object to never become
> garbage when the dictionary against which tstdel2.py is executed
> is clear()'d.
>
> It is possible that this bug is related to the 'NameError: tracer'
> I posted earlier (I gave up to isolate this possible bug).
> If/when these two are related a possible explanation would be
> that in some execution frame there is a wrong reference to an
> earlier frame. This could in this case form a dangling reference
> and in the 'NameError: tracer' case cause a deletion from the
> wrong namespace.
>
> Again, I do hope that this one is platform dependent.
> If not, I'll gladly report a bug on sourceforge...
>
> Have fun,
> Ype
>
> P.S. 21b1 is otherwise working very well for me.
>
> _______________________________________________
> Jython-dev mailing list
> Jyt...@li...
> https://lists.sourceforge.net/lists/listinfo/jython-dev
>
|
|
From: <bc...@wo...> - 2001-12-18 10:52:21
|
[Ype Kingma] >Dear jythoneers, > >This is a rather involved bug, so I hope it is JVM dependent. >It shows up in rather unusual circumstances. [example running __del__() method in clear globals snipped] It isn't really a mystery and exactly the same thing happens in CPython. When the __del__() is executed, the globals no longer have a reference to the module level println function. The result is a common NameError exception. Unfortunately Jython 2.1b1 doesn't inform you of the exception in the way it should. When I fix that bug, your program will the same way, but it will write: __main__.executor Hello <<unknown>.deltest1 instance at 6467398> Hello2 <<unknown>.deltest2 instance at 5935979> after del __main__.executor Goodbye <<unknown>.deltest1 instance at 6467398> Goodbye2 <<unknown>.deltest2 instance at 5935979> __main__.clearingExecutor Hello <<unknown>.deltest1 instance at 13226366> Goodbye <<unknown>.deltest1 instance at 13226366> Hello2 <<unknown>.deltest2 instance at 14919969> Exception NameError: println in <unbound method deltest2.__del__> ignored after del __main__.clearingExecutor which at least contain a usefull hint about the real problem. Thanks for making the example available. Without it, the bug would never have been uncovered this easily. regards, finn |
|
From: Samuele P. <ped...@bl...> - 2001-12-18 11:31:27
|
> > Unfortunately Jython 2.1b1 doesn't inform you of the exception in the > way it should. When I fix that bug, your program will the same way, but > it will write: > The point is that java simply discards the exceptions thrown in finalizers. So we should catch them and print them explicitly for the __del__ invocation in the finalizer. OTOH there is no leak. regards, Samuele Pedroni. |