无论我尝试使用PyV8,总是会出现大量内存泄漏。即使使用空字符串执行eval,它似乎仍然会以某种方式泄漏内存。在下面发布的示例中,使用空字符串执行的1000万次eval生成320MB的内存,此后在显式调用垃圾回收器时仅会收集20MB的内存。上下文是否可以访问对于我来说似乎并没有什么不同。我已经用类似的测试测试了我的python本身,并且它不会泄漏内存。难道我做错了什么?
版本号
PyV8修订版557,使用PyV8的setup.py在同一台计算机上构建
V8修订版19632,使用PyV8的setup.py在同一台计算机上构建
操作系统:Ubuntu 12.04
测试码
import unittest, gc, os, logging as python_logging
from PyV8 import JSEngine, JSContext
_proc_status = '/proc/%d/status' % os.getpid()
_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
'KB': 1024.0, 'MB': 1024.0*1024.0}
def log_memory_usage(intro_text=""):
python_logging.info(
(
'%s process %d now uses %.1f MB resident'
%(intro_text, os.getpid(), resident()/(1024*1024))
).strip()
)
def _VmB(VmKey):
'''Private.
'''
global _proc_status, _scale
# get pseudo file /proc/<pid>/status
try:
t = open(_proc_status)
v = t.read()
t.close()
except:
return 0.0 # non-Linux?
# get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
i = v.index(VmKey)
v = v[i:].split(None, 3) # whitespace
if len(v) < 3:
return 0.0 # invalid format?
# convert Vm value to bytes
return float(v[1]) * _scale[v[2]]
def resident(since=0.0):
'''Return resident memory usage in bytes.
'''
return _VmB('VmRSS:') - since
class TestMemoryWithJSContext(unittest.TestCase):
def test_python_memory_management(self):
def inner():
with JSContext() as ctx:
log_memory_usage("before empty evals")
for index1 in range(1000):
for index2 in range(10000):
ctx.eval("")
log_memory_usage("after empty evals")
JSEngine.collect()
log_memory_usage("before JSContext memory tests")
inner()
JSEngine.collect()
gc.collect()
JSEngine.collect()
gc.collect()
log_memory_usage("after JSContext memory tests and gc")
print "Py gc.garbage:", gc.garbage
class CardEngineTestSuite(unittest.TestSuite):
def __init__(self):
super(CardEngineTestSuite, self).__init__()
self.addTests(unittest.TestLoader().loadTestsFromTestCase(TestPython))
self.addTests(unittest.TestLoader().loadTestsFromTestCase(TestMemoryWithJSContext))
if __name__ == '__main__':
python_logging.basicConfig(level=python_logging.INFO, format='%(asctime)s %(message)s')
unittest.TextTestRunner().run(CardEngineTestSuite())
unittest.TextTestRunner().run(CardEngineTestSuite())
python_logging.info(str(gc.garbage))
输出量
.2014-03-28 21:41:34,198 before JSContext memory tests process 110 now uses 14.1 MB resident
2014-03-28 21:41:34,199 before empty evals process 110 now uses 14.4 MB resident
2014-03-28 21:41:55,513 after empty evals process 110 now uses 348.8 MB resident
2014-03-28 21:41:56,926 after JSContext memory tests and gc process 110 now uses 322.3 MB resident
Py gc.garbage: []
.
----------------------------------------------------------------------
Ran 2 tests in 26.838s
OK
.2014-03-28 21:42:01,103 before JSContext memory tests process 110 now uses 322.5 MB resident
2014-03-28 21:42:01,104 before empty evals process 110 now uses 322.5 MB resident
2014-03-28 21:42:25,714 after empty evals process 110 now uses 636.5 MB resident
2014-03-28 21:42:28,459 after JSContext memory tests and gc process 110 now uses 629.3 MB resident
Py gc.garbage: []
.
----------------------------------------------------------------------
Ran 2 tests in 31.532s
OK
最佳答案
以下PyV8票证中描述的答案为我解决了该问题-尽管垃圾回收现在占用了大量CPU时间。为了解决这个问题,我将PyV8代码移到了一个芹菜工作者中,并让它在后台进行垃圾收集。如果您想查看此代码,请联系我,现在我真的没有时间准备示例代码。
https://code.google.com/p/pyv8/issues/detail?id=229&sort=-id