Quantcast
Channel: ClearScript
Viewing all articles
Browse latest Browse all 2297

New Post: memory leak when passing javascript object to managed code

0
0
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
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.js
var 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

Viewing all articles
Browse latest Browse all 2297

Latest Images

Trending Articles





Latest Images