code-google-com / pyv8

Automatically exported from code.google.com/p/pyv8
0 stars 0 forks source link

Calling python func on a python object from javascript permanently increases reference count, leading to memory leaks. #185

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Run the following code (also attached)

import sys

import PyV8

class ProxyObj(object):
    def __init__(self):
        pass

    def what(self):
        pass

class Global(object):
    def Obj(self):
        return ProxyObj()

def case1():
    ctxt = PyV8.JSContext(Global())
    with ctxt:
        obj = ctxt.eval("""function foo() {
            var theObj = Obj();
            return theObj;
        }
        var res = foo();
        res;
        """)
        print "Case 1:", sys.getrefcount(obj)

def case2():
    ctxt = PyV8.JSContext(Global())
    with ctxt:
        obj = ctxt.eval("""function foo() {
            var theObj = Obj();
            theObj.what();
            theObj.what();
            theObj.what();
            return theObj;
        }
        var res = foo();
        res;
        """)
        print "Case 2:", sys.getrefcount(obj)

case1()
case2()

What is the expected output? What do you see instead?

I would expect:

Case 1: 3
Case 2: 3

Because there should be 3 references to the object: The local python var 'obj', 
the reference from V8, and the reference that 'getrefcount' has while it's 
running.

I instead see:

Case 1: 3
Case 2: 6

What version of the product are you using? On what operating system?

Using Python 2.6.6 with PyV8-1.0-preview-r443.win32-py2.6.exe on Windows 7

Please provide any additional information below.

Inserting a "PyV8.JSEngine.collect()" call doesn't fix the issue.

Original issue reported on code.google.com by csaft...@gmail.com on 17 Jul 2013 at 4:40

Attachments:

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
Note that the same happens if Global and ProxyObj inherit from PyV8.JSClass vs. 
from object. 

The same also happens without having the function `foo` involved. That is:

var theObj = Obj();
theObj.what();
theObj.what();
theObj.what();
theObj;

Original comment by csaft...@gmail.com on 17 Jul 2013 at 4:42

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
* If ProxyObj inherits from JSObject, same behavior. 

* The function doesn't have to be called. If this is Case 2 , you get the same 
output:

                        var theObj = Obj();
                        theObj.what;
                        theObj.what;
                        theObj.what;
                        theObj;

* If 'what' is a variable or a function/not an instance method, bug doesn't 
happen, i.e.:

class ProxyObj(object):
    def __init__(self):
        self.what = None

or

def f():
    pass

class ProxyObj(object):
    def __init__(self):
        self.what = f

* It also doesn't happen if I make a 'fake' instance method:

def f(self):
    pass

class ProxyObj(object):
    def __init__(self):
        self.what = lambda: f(self)

In this case the reference counts are both '4'. 

* No bug if it's a static method or classmethod:

class ProxyObj(object):
    def __init__(self):
        pass

    @staticmethod
    def what():
        pass

or

class ProxyObj(object):
    def __init__(self):
        pass

    @classmethod
    def what():
        pass

In both cases, both cases are '3'.

* Basically seems to be an instancemethod issue.

Original comment by csaft...@gmail.com on 17 Jul 2013 at 4:52

GoogleCodeExporter commented 9 years ago
* @property is also not a problem, that is:

class ProxyObj(object):
    def __init__(self):
        pass

    @property
    def what(self):
        return 100

Doesn't cause the leak

Original comment by csaft...@gmail.com on 17 Jul 2013 at 5:48