This project is read-only.

Isolated Execution Environments

Dec 2, 2015 at 8:55 AM
Hi all, I was hoping you could help me with a little issue we seem to be having.

We have a piece of software that executes a load of Javascripts through the use of a V8Engine. The problem arises that each script needs to have it's own execution environment, but ran through the same instance of the V8Engine, I was wondering if this was possible ?

At the moment our current solution is to dispose and re-instantiate the engine for each script, which is increasing our run time by a great deal (We're running about 2000 scripts at the moment and it's taking about 5x longer than it did prior to V8Engine).

The ideal solution would be some kind of V8Engine.Clear() method that would refresh the environment so that each execution was in it's own 'isolated' environment. Otherwise we run into issues where variables share names between scripts and it shows an error when the second script tries to 're-declare' it.

Below is our current implementation, sorry if my explanation isnt very clear, if you have any questions feel free to ask
        public string Execute(string script)
        {
            string result = "";

            try
            {
                //  EVALUATE THE SCRIPT

                //You have to create the engine again before each script, or you run into the issue of it 'remembering'
                //which variables have been declared in previous scripts
                //Create the V8Engine and dispose when done
                using (m_engine = new V8Engine())
                {
                    //Set the Lookup instance as a global object so that the JS code in the V8.Net wrapper can access it
                    m_engine.GlobalObject.SetProperty("Lookup", m_lookup, null, true, ScriptMemberSecurity.Permanent);
                    //Execute the script
                    result = m_engine.Execute(script);
                }
            }
            catch (Exception ex)
            {
                // V8.NET error?
                if (ex.Source.CompareTo("V8.Net") == 0)
                {
                    // Yes, turn it into a Race V8 Exception to avoid a stack trace dump.
                    throw (V8Exception)ex;
                }
                // Not a V8 error, so just re-throw exception.
                throw ex;
            }

            return result;
        }
Dec 7, 2015 at 12:06 PM
I have also just noticed that the above code is causing a memory leak of some kind, and Im not really sure why or where :(
Dec 10, 2015 at 1:19 AM
Ok, I'll take a look ASAP, thanks. ;)
Dec 10, 2015 at 10:27 AM
Edited Dec 10, 2015 at 10:35 AM
jamesnw wrote:
Ok, I'll take a look ASAP, thanks. ;)
Thanks!
Not sure how useful this will be but I've been running some memory profiling tools on it and have learnt that after running an isolated version of the original code, My software ends up with a large amount of instances of IndexedObjectList's full of null values (see here: http://imgur.com/a/bll5K). It appears to have one instance of each class for each V8Engine instance that is made, but they aren't being disposed or freed. I cant help but feel like I'm missing a command or something here.
The code I'm using to test and recreate the memory leak that the above implementation causes is as follows:
using System;
using V8.Net;

namespace V8DotNetMemoryTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string script = @"  var math1 = 5;
                                var math2 = 10;
                                result = 5 + 10;";
            Handle result;
            int i = 0;
            V8Engine local_m_engine;
            while (true)
            {
                //Create the V8Engine and dispose when done
                local_m_engine = new V8Engine();
                
                //Set the Lookup instance as a global object so that the JS code in the V8.Net wrapper can access it
                //local_m_engine.GlobalObject.SetProperty("Lookup", m_lookup, null, true, ScriptMemberSecurity.ReadOnly);
                //Execute the script
                result = local_m_engine.Execute(script);
                Console.WriteLine(i++);

                result.ReleaseManagedObject();
                result.Dispose();

                local_m_engine.Dispose();
                GC.WaitForPendingFinalizers();
                GC.Collect();
                
                local_m_engine = null;
                
            }
        }
    }
}
I'm hoping finding a way to clear the environment's context will solve this issue as I wont have to re-instantiate the Engine each time (and so end up with this memory leak) but if that's not a possibility with the current implementation then I hope you can point me in a direction to solve this issue instead?
Thanks a lot :)
Dec 10, 2015 at 3:37 PM
Thanks for the extra details. I do plan to put in context switching to make this easier, so only a single engine would be needed.
Dec 10, 2015 at 3:49 PM
jamesnw wrote:
Thanks for the extra details. I do plan to put in context switching to make this easier, so only a single engine would be needed.
Brilliant! Until then do you have any idea how I could solve this memory leak as a temporary solution ? :)
Dec 12, 2015 at 7:18 AM
Not really - this may be a bug somewhere. I'll have to investigate first.
Jun 1, 2016 at 7:40 AM
Hi, I have same problem. Did you find some solution (workaround)?
Jun 2, 2016 at 9:08 AM
Sorry, I haven't had time to work on this yet, but I have another project that will require this soon so I'll be getting back into it shortly.
Jun 2, 2016 at 9:27 AM
Jack13 wrote:
Hi, I have same problem. Did you find some solution (workaround)?
I thought I replied via email but I guess not, I found an alternate solution using another open source engine called 'Jint' that solved my issue. Hope this helps!