nerdneilsfield / pyv8

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

returning a javascript object containing a python object from a python function called from javascript causes a memory leak #188

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

Run the following code (also attached);

import gc
import weakref

import PyV8

tracks = {} #map weakref id to (weakref, description)
def tracked_deleted(r):
    _, descr = tracks[id(r)]
    print ("Tracked object '%s' just deleted." % (descr,))
    del tracks[id(r)]
def track(o, descr):
    r = weakref.ref(o, tracked_deleted)
    tracks[id(r)] = (r, "%s:%s" % (o.__class__.__name__, descr))
    return o

class EmptyProxy(object):
    pass

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

    def track(self, obj, descr):
        return track(obj, descr)

    def out(self, v):
        assert isinstance(v, str)        
        print "-- Script out: %s --" % (v,)

    def returnArg(self, arg):
        return arg

    def doNothing(self, arg):
        pass

    def Empty(self):
        return EmptyProxy()

def run_case(name, js_setup, js_cleanup):
    print "Case '%s':" % (name,)
    ctxt = PyV8.JSContext(Global())
    with ctxt:
        print "  Runnning setup"
        ctxt.eval(js_setup)

        print "  Running cleanup"
        ctxt.eval(js_cleanup)
        print "  V8 gc"
        PyV8.JSEngine.collect()
        print "  Py gc"
        gc.collect()
        print "  V8 gc"
        PyV8.JSEngine.collect()
        print "  Py gc"
        gc.collect()
        print "  Py gc.garbage:", gc.garbage
    print

gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE |
             gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)

run_case("tracktest", """
    var x = track(Empty(), "OK");
""", """x = null;""")

run_case("return js obj with py in it", """

var pyObj = track(Empty(), "yes GC cause returning py obj");
returnArg(pyObj);

var jsWithPy = {obj: track(Empty(), "yes GC cause returning py obj")};
returnArg(jsWithPy.obj);

var jsWithPy2 = {obj: track(Empty(), "no GC cause returning js obj with py obj 
in it")};
returnArg(jsWithPy2);

""", """
pyObj = null;
jsWithPy = null;
jsWithPy2 = null;
""")

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

The first case is just to show how my testing mechanism works:

Case 'tracktest':
  Runnning setup
  Running cleanup
  V8 gc
Tracked object 'EmptyProxy:OK' just deleted.
  Py gc
  V8 gc
  Py gc
  Py gc.garbage: []

For the second case I would expect all 3 objects to be GCd:

Case 'return js obj with py in it':
  Runnning setup
  Running cleanup
  V8 gc
Tracked object 'EmptyProxy:yes GC cause returning py obj' just deleted.
Tracked object 'EmptyProxy:yes GC cause returning py obj' just deleted.
Tracked object 'EmptyProxy:no GC cause returning js obj with py obj in it' just 
deleted.
  Py gc
  V8 gc
  Py gc
  Py gc.garbage: []

However, the "no GC cause returning js obj with py obj in it" is not freed.

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

PyV8 r443 with Python 2.6.6 on Windows 7

Please provide any additional information below.

PyV8 has a lot of memory leak issues!

Original issue reported on code.google.com by csaft...@gmail.com on 18 Jul 2013 at 7:53