finalizers depend on Java import
"Stefan Richthofer" <[email protected]>
| Newsgroups | gmane.comp.lang.jython.devel |
|---|---|
| Message-ID | <trinity-8865227f-a0f6-4c63-be37-b29d3f24f271-1408397275676@3capp-gmx-bs66> |
I did more experiments and created a unit test for this phenomenon. If nobody can explain this behavior, I would consider it a memory leak and file a bug. Let me comprehend my observations: An import between A = SomeClass() and A = None causes A to be kept alive for some reason, if gc runs after that. Interestingly it appears that another import after A = None releases this alive-keeping (see test_clear_object_surround_java_import_2 in the attached file), unless this subsequent import happens in another method (test_clear_object_surround_java_import_3). It seems to make no difference, whether the imports are Java or Python imports. I know this is probably of rare interest, since it is a really strange scenario to perform imports at such places. However, I find this behavior strange enough to indicate that something is not sufficiently understood/something is not working cleanly. Since I am currently fixing finalizer issues and don't want to overlook something, I would prefer to understand this despite the maybe rare common interest. Somehow the import process establishes a strong reference to A, keeping it alive. I suspect it might be hard to find out how this happens. So if someone more familiar with Jython's import process could point me somewhere, this would be helpful. Stefan Gesendet: Samstag, 16. August 2014 um 22:49 Uhr Von: "Stefan Richthofer" <[email protected]> An: "Jython Developers" <[email protected]> Betreff: finalizers depend on Java import Hello everybody, I am currently doing experiments how Jython behaves regarding to finalizers (with the goal to develop a fix for issue 1057). However I observed the following strange behavior. When I encapsulate the java import in test_finalizer_builtin_oldStyleClass (see program appended at the bottom) like this A = DummyClass("A") if platform.system() == "Java": from java.lang import System #print System.identityHashCode(A) A = None runGCIfJython() the test in the appended program fails. But these variants both pass: A = DummyClass("A") A = None if platform.system() == "Java": from java.lang import System #print System.identityHashCode(A) runGCIfJython() if platform.system() == "Java": from java.lang import System #print System.identityHashCode(A) A = DummyClass("A") A = None runGCIfJython() I know, it is not so beautiful to do imports at arbitrary positions in the program, but afaIk it should still work and encapsulating Java imports produces a program that can be cross-tested in CPython without modification - so it's rather handy. The line print System.identityHashCode(A) was the original usecase, but could be removed whithout changing the strange behavior. Does somone have any clue how this comes? Does the import establish some obscure reference to A that keeps it alive? But why does this only happen if the import happens after between A = DummyClass("A") and A = None? I looked through the Jython code, but could not yet find that a Java-import would cache existing Python objects or something. I am sure that the gc actually runs, since I also tested the variant A = DummyClass("A") if platform.system() == "Java": from java.lang import System #print System.identityHashCode(A) A = None B = DummyClass("B") B = None runGCIfJython() It prints "B finalized (DummyClass)", so B is finalized as expected and A not. Thanks in advance for any hints! Stefan import platform import unittest import time def runGCIfJython(): if platform.system() == "Java": from java.lang import System System.gc() time.sleep(0.1) finalizeMsgList = [] class DummyClass(): def __init__(self, name): self.name = name def __str__(self): return self.name def __del__(self): finalizeMsgList.append(str(self)+" finalized (DummyClass)") print str(self)+" finalized (DummyClass)" class TestFinalizers(unittest.TestCase): def test_finalizer_builtin_oldStyleClass(self): A = DummyClass("A") if platform.system() == "Java": from java.lang import System #print System.identityHashCode(A) A = None runGCIfJython() assert("A finalized (DummyClass)" in finalizeMsgList) if __name__ == '__main__': unittest.main() ------------------------------------------------------------------------------ _______________________________________________ Jython-dev mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/jython-dev
test_finalizer_vs_import.py
(text/x-python, 2.3 KB)
import platform
import unittest
import time
if platform.system() == "Java":
from java.lang import System
class GCDetector():
gcIndex = 0
def __del__(self):
GCDetector.gcIndex += 1
#maxGCRun = 10
def runGCIfJython():
if platform.system() == "Java":
currentIndex = GCDetector.gcIndex
gcCount = 0
detector = GCDetector()
detector = None
while currentIndex == GCDetector.gcIndex: #and gcCount < maxGCRun:
System.gc()
gcCount += 1
time.sleep(0.1)
def runGCIfJythonWithImport():
import datetime
runGCIfJython()
finalizeMsgList = []
class DummyClass():
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __del__(self):
finalizeMsgList.append(str(self)+" finalized (DummyClass)")
print str(self)+" finalized (DummyClass)"
class TestFinalizers(unittest.TestCase):
def test_clear_object_before_import(self):
A = DummyClass("A")
A = None
import time
runGCIfJython()
assert("A finalized (DummyClass)" in finalizeMsgList)
def test_clear_object_after_import(self):
import time
B = DummyClass("B")
B = None
runGCIfJython()
assert("B finalized (DummyClass)" in finalizeMsgList)
def test_clear_object_surround_import(self):
C = DummyClass("C")
import time
C = None
runGCIfJython()
assert("C finalized (DummyClass)" in finalizeMsgList)
def test_clear_object_surround_java_import(self):
D = DummyClass("D")
if platform.system() == "Java":
from java.lang import String
D = None
runGCIfJython()
assert("D finalized (DummyClass)" in finalizeMsgList)
def test_clear_object_surround_java_import_2(self):
E = DummyClass("E")
import time
E = None
import datetime
runGCIfJython()
assert("E finalized (DummyClass)" in finalizeMsgList)
def test_clear_object_surround_java_import_3(self):
F = DummyClass("F")
import time
F = None
#import datetime
runGCIfJythonWithImport()
assert("F finalized (DummyClass)" in finalizeMsgList)
if __name__ == '__main__':
unittest.main()