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()
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.