Taritsyn / JavaScriptEngineSwitcher

JavaScript Engine Switcher determines unified interface for access to the basic features of popular JavaScript engines. This library allows you to quickly and easily switch to using of another JavaScript engine.
Apache License 2.0
440 stars 49 forks source link

JavaScriptEngineSwitcher.Core.JsRuntimeException: Out of memory. #35

Closed ashkansiroos closed 5 years ago

ashkansiroos commented 7 years ago

Hi Andrey, First of, thanks for the awesome libraries. YOU ROCK!

Secondly, I have reactjs.net installed with JavaScriptEngineSwitcher.Core and JavaScriptEngineSwitcher.ChakraCore. I've tried an stress test and IIS stopped working after 2 hours. saying:

JavaScriptEngineSwitcher.Core.JsRuntimeException: Out of memory. Line: 0 Column:0 at React.ReactEnvironment.Execute[T](String code)

Unfortunately because of the wrapper around the exception, I cannot say what is causing it. To investigate more, I tried different scenarios and I've found out when I add a space into web.config which will cause the IIS to restart the application, the IIS thread will start growing little by little and after a while IIS will crash even if the stress test is stopped with error:

Application: w3wp.exe Framework Version: v4.0.30319 Description: The process was terminated due to an internal error in the .NET Runtime at IP 5A3A86F1 (5A0F0000) with exit code 80131506.

and

Faulting application name: w3wp.exe, version: 10.0.15063.0, time stamp: 0xacce422f Faulting module name: clr.dll, version: 4.7.2098.0, time stamp: 0x59028d36 Exception code: 0xc0000005 Fault offset: 0x002b86f1 Faulting process id: 0x50a4 Faulting application start time: 0x01d2ee688f323893 Faulting application path: C:\WINDOWS\SysWOW64\inetsrv\w3wp.exe Faulting module path: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll Report Id: 4362ddc5-f8d7-4441-8916-3830f9268b3a Faulting package full name: Faulting package-relative application ID:

I've also made a post on stack-overflow, but I wasn't sure what is causing this and if it is the EngineSwitcher, or the JSPool that causes the error so I've just described the situation.

https://stackoverflow.com/questions/44759636/finding-memory-leak?noredirect=1#comment76500449_44759636

Taritsyn commented 7 years ago

Hello, Ashkan!

Most likely, reason for this error is that your web application is not enough memory.

There are two ways to solve this problem:

  1. Increase application pool size.
  2. Optimize executable JavaScript code.
Taritsyn commented 7 years ago

Unfortunately because of the wrapper around the exception, I cannot say what is causing it.

In next release I will add the original exception as the inner exception.

ashkansiroos commented 7 years ago

@Taritsyn Thanks for the fast reply. But if that is the case, why my IIS memory usage is growing all the time? It easily gets to 2GB of RAM after half an hour for 15 pages with stress testing and it keeps growing little by little until I stop the test. Any idea about that?

Taritsyn commented 7 years ago

Why did you decide, that the cause of memory leak is the JavaScriptEngineSwitcher.ChakraCore? Have you tried to use the JavaScriptEngineSwitcher.V8 instead of the JavaScriptEngineSwitcher.ChakraCore?

Taritsyn commented 7 years ago

In next release I will add the original exception as the inner exception.

This functionality is implemented in version 2.4.7.

ashkansiroos commented 7 years ago

Why did you decide, that the cause of memory leak is the JavaScriptEngineSwitcher.ChakraCore I didn't :) I didn't have the stack trace so I really don't know.

I've tried to install version 2.4.7 but as you know JSPool 2.0.1 is not compatible with JavaScriptEngineSwitcher 2.4 and adding ".AddChakraCore()" or "engineSwitcher.DefaultEngineName = ChakraCoreJsEngine.EngineName" didn't help so I'm cloning the "JSPool" and "React" project to see how far I can go with the tracing and testing.

Taritsyn commented 7 years ago

… or "engineSwitcher.DefaultEngineName = ChakraCoreJsEngine.EngineName" …

This feature is not supported by current version of the React.NET (read discussion).

… didn't help …

Just need to configure the JavaScript Engine Switcher before registration of the React.NET (see Daniel's comment).

ashkansiroos commented 7 years ago

@Taritsyn I've read Daniel's comment several times before I try to clone the project and based on that I have:

    public class JsEngineSwitcherConfig
    {
        public static void Configure(JsEngineSwitcher engineSwitcher)
        {
            engineSwitcher.EngineFactories.AddChakraCore();
            engineSwitcher.DefaultEngineName = ChakraCoreJsEngine.EngineName;
        }
    }

But I get the exception below, so I guess I didn't understand what he meant. Could you please help me with that?

  • System.TypeLoadException: Method 'Evaluate' in type 'JSPool.JsEngineWithOwnThread' from assembly 'JSPool, Version=2.0.1.0, Culture=neutral, PublicKeyToken=2fc7775f73072640' does not have an implementation.
Taritsyn commented 7 years ago

Where you call the JsEngineSwitcherConfig.Configure method?

ashkansiroos commented 7 years ago

In my Application_start() in my global.asax

Taritsyn commented 7 years ago

Give an example of the Application_start() code.

ashkansiroos commented 7 years ago
    protected void Application_Start()
        {
            Logger.Warning("Application Start");
            GlobalConfiguration.Configure(WebApiConfig.Register);

            AreaRegistration.RegisterAllAreas();
            JsEngineSwitcherConfig.Configure(JsEngineSwitcher.Instance);
         }
ashkansiroos commented 7 years ago

just to add some info: .net framework: 4.6.2 IIS 10 on Windows 10.

Taritsyn commented 7 years ago

Move the call of JsEngineSwitcherConfig.Configure method from a global.asax file into the App_Start/ReactConfig.cs file (before all the React.NET settings).

ashkansiroos commented 7 years ago

The same error happens:


[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(ReactConfig), "Configure")]
namespace MyNamespace
{
 public static class ReactConfig
    {
        public static void Configure()
        {
            JsEngineSwitcherConfig.Configure(JsEngineSwitcher.Instance);
            ReactSiteConfiguration.Configuration.SetLoadBabel(false).SetJsonSerializerSettings(JsonSerialization.Settings).AddScriptWithoutTransform("~/server.bundle.js");
        }

        public class JsonSerialization
        {
            public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore,
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };

        }
    }
}

and now my Application_Start looks like this:

    protected void Application_Start()
        {
            Logger.Warning("Application Start");
            GlobalConfiguration.Configure(WebApiConfig.Register);
            AreaRegistration.RegisterAllAreas();
        }
Taritsyn commented 7 years ago

App_Start/ReactConfig.cs file has the [assembly: WebActivatorEx.PreApplicationStartMethod(typeof(...), "Configure")] attribute?

ashkansiroos commented 7 years ago

Yes, It is also a part of the code snippet that I've added on my last comment

Taritsyn commented 7 years ago

Rebuild solution and clear browser cache. It should work correctly.

ashkansiroos commented 7 years ago

@Taritsyn thanks for the help. I could run the test with JavaScriptEngineSwitcher.ChakraCore v2.4.7 and I reproduced the error. However, it still doesn't have much more information:

2017-06-28 13:27:10,230 [273] ERROR Website.Extentions.HtmlExtentions: Error rendering react component x with model y JavaScriptEngineSwitcher.Core.JsRuntimeException: Script threw an exception: Out of memory Line: 1 Column:1 at React.ReactEnvironment.Execute[T](String code) at Website.JS.execute(String code) JavaScriptEngineSwitcher.Core.JsRuntimeException: Script threw an exception: Out of memory Line: 1 Column:1 at React.ReactEnvironment.Execute[T](String code) at Website.JS.execute(String code)

Also when it throws the exception, I break the code in Visual studio and this is what it has:

    $exception  {"Script threw an exception: Out of memory\r\nLine: 1\r\nColumn:1"}
JavaScriptEngineSwitcher.Core.JsRuntimeException

    EngineName  "ChakraCoreJsEngine"    string
    EngineVersion   "1.5.2" string
    ErrorCode   "196609"    string
    HResult -2146233088 int
Taritsyn commented 7 years ago

Hello, Ashkan!

This problem is caused by current implementation of the WrapJavaScriptRuntimeException method of ReactEnvironment class:

/// <summary>
/// Updates the Message of a <see cref="JsRuntimeException"/> to be more useful, containing
/// the line and column numbers.
/// </summary>
/// <param name="ex">Original exception</param>
/// <returns>New exception</returns>
protected virtual JsRuntimeException WrapJavaScriptRuntimeException(JsRuntimeException ex)
{
    return new JsRuntimeException(string.Format(
        "{0}\r\nLine: {1}\r\nColumn:{2}",
        ex.Message,
        ex.LineNumber,
        ex.ColumnNumber
    ), ex.EngineName, ex.EngineVersion)
    {
        ErrorCode = ex.ErrorCode,
        Category = ex.Category,
        LineNumber = ex.LineNumber,
        ColumnNumber = ex.ColumnNumber,
        SourceFragment = ex.SourceFragment,
        Source = ex.Source,
    };
}

During wrapping loses information about the inner exception.

Taritsyn commented 5 years ago

Hello, Ashkan!

I think that after release of the JavaScript Engine Switcher 3.0 and ReactJS.NET 4.0, you can close this issue.