eukreign / python-v8

Apache License 2.0
12 stars 6 forks source link

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

Open eukreign opened 10 years ago

eukreign commented 10 years ago

From csaft...@gmail.com on July 17, 2013 12:40:13

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.

Attachment: pyv8-bug.py

Original issue: http://code.google.com/p/pyv8/issues/detail?id=185

eukreign commented 10 years ago

From csaft...@gmail.com on July 17, 2013 09:42:55

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;

eukreign commented 10 years ago

From csaft...@gmail.com on July 17, 2013 09:52:46

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

or

def f(): pass

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

def f(self): pass

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

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

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'.

eukreign commented 10 years ago

From csaft...@gmail.com on July 17, 2013 10:48:14

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

@property
def what(self):
    return 100

Doesn't cause the leak