I am seeing a memory leak when passing a javascript object to a managed code function. I am using the latest nuget clearscript V8. Please see below for the code that reproduces this issue.
Program.cs
Am I doing something wrong with this code? If not, is there any workaround for this issue?
thanks,
Tom
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;
namespace ClearScriptMemoryLeak
{
public class Program
{
protected V8ScriptEngine m_engine;
public Program(V8ScriptEngine engine)
{
m_engine = engine;
}
public void doSomething(dynamic foo)
{
}
public void garbageCollect()
{
V8RuntimeHeapInfo beforeInfo = m_engine.GetRuntimeHeapInfo();
m_engine.CollectGarbage(true);
V8RuntimeHeapInfo afterInfo = m_engine.GetRuntimeHeapInfo();
Console.WriteLine("garbageCollect: memstats (before/after): used: " + beforeInfo.UsedHeapSize + "/" + afterInfo.UsedHeapSize);
}
public static String loadScript(String filePath)
{
StringBuilder builder = new StringBuilder();
FileInfo fileInfo = new FileInfo(filePath);
using (StreamReader sr = fileInfo.OpenText())
{
String s = "";
while ((s = sr.ReadLine()) != null)
{
builder.AppendLine(s);
}
}
return builder.ToString();
}
static void Main(string[] args)
{
V8ScriptEngine engine = new V8ScriptEngine(V8ScriptEngineFlags.EnableDebugging);
Program p = new Program(engine);
engine.AddHostObject("nativeBridge", p);
engine.Execute(loadScript(args[0]));
}
}
}
MemLeak.jsvar count = 0;
var obj;
while (true) {
if (++count % 10000 == 0) {
nativeBridge.garbageCollect();
}
obj = {
a: "b",
c: "d"
};
nativeBridge.doSomething(obj);
}
Running the above javascript will eventually crash with the following exception:garbageCollect: memstats (before/after): used: 227850008/227529964
garbageCollect: memstats (before/after): used: 228050008/227729964
garbageCollect: memstats (before/after): used: 228250008/227929964
garbageCollect: memstats (before/after): used: 228450008/228129964
Unhandled Exception: Microsoft.ClearScript.ScriptEngineException: Error: Exception of type 'System.OutOfMemoryException' was thrown. ---> System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at Microsoft.ClearScript.HostItem.AdjustInvokeFlags(BindingFlags& invokeFlags)
at Microsoft.ClearScript.HostItem.InvokeMember(String name, BindingFlags invokeFlags, Object[] args, Object[] bindArgs, CultureInfo culture, Boolean bypassTunneling, Boolean& isCacheable)
at Microsoft.ClearScript.HostMethod.TryInvoke(IHostInvokeContext context, BindingFlags invokeFlags, Object[] args, Object[] bindArgs, Object& result)
at Microsoft.ClearScript.Util.InvokeHelpers.TryInvokeObject(IHostInvokeContext context, Object target, BindingFlags invokeFlags, Object[] args, Object[] bindArgs, Boolean tryDynamic, Object& result)
at Microsoft.ClearScript.HostItem.InvokeHostMember(String name, BindingFlags invokeFlags, Object[] args, Object[] bindArgs, CultureInfo culture, Boolean& isCacheable)
at Microsoft.ClearScript.HostItem.InvokeMember(String name, BindingFlags invokeFlags, Object[] args, Object[] bindArgs, CultureInfo culture, Boolean bypassTunneling, Boolean& isCacheable)
at Microsoft.ClearScript.HostItem.<>c__DisplayClass4b.<InvokeReflectMember>b__4a()
at Microsoft.ClearScript.ScriptEngine.HostInvoke[T](Func`1 func)
at Microsoft.ClearScript.HostItem.HostInvoke[T](Func`1 func)
at Microsoft.ClearScript.HostItem.InvokeReflectMember(String name, BindingFlags invokeFlags, Object[] wrappedArgs, CultureInfo culture, String[] namedParams, Boolean& isCacheable)
at Microsoft.ClearScript.HostItem.System.Reflection.IReflect.InvokeMember(String name, BindingFlags invokeFlags, Binder binder, Object invokeTarget, Object[] wrappedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at Microsoft.ClearScript.HostItem.Microsoft.ClearScript.Util.IDynamic.Invoke(Object[] args, Boolean asConstructor)
at HostObjectHelpers.Invoke(V8Value* , Void* pvObject, vector<V8Value\,std::allocator<V8Value> >* args, Boolean asConstructor)
--- End of inner exception stack trace ---
at V8Exception.ThrowScriptEngineException(V8Exception* )
at Microsoft.ClearScript.V8.V8ContextProxyImpl.Execute(String gcDocumentName, String gcCode, Boolean evaluate, Boolean discard)
at Microsoft.ClearScript.V8.V8ScriptEngine.<>c__DisplayClass1b.<Execute>b__19()
at Microsoft.ClearScript.ScriptEngine.ScriptInvoke[T](Func`1 func)
at Microsoft.ClearScript.V8.V8ScriptEngine.BaseScriptInvoke[T](Func`1 func)
at Microsoft.ClearScript.V8.V8ScriptEngine.<>c__DisplayClass25`1.<ScriptInvoke>b__24()
at Microsoft.ClearScript.V8.?A0x792c8756.InvokeAction(Void* pvActionRef)
at Microsoft.ClearScript.V8.V8ContextProxyImpl.InvokeWithLock(Action gcAction)
at Microsoft.ClearScript.V8.V8ScriptEngine.ScriptInvoke[T](Func`1 func)
at Microsoft.ClearScript.V8.V8ScriptEngine.Execute(String documentName, String code, Boolean evaluate, Boolean discard)
at Microsoft.ClearScript.ScriptEngine.Execute(String code)
If I remove the 'nativeBridge.doSomething(obj);' line, then there is no memory leak. Likewise, if I move the "obj = {...}" statement outside of the while loop, there is no leak.Am I doing something wrong with this code? If not, is there any workaround for this issue?
thanks,
Tom