Taritsyn/MsieJavaScriptEngine

Block finalizer solved?

comprosedev opened this issue · 8 comments

After doing an analysis of one of our Memory dumps, Microsoft stated this.

_However for your specific instance your finalizer thread is blocked by a ChakraEdgeJsRtJsEngine object. When looking at the amount of exceptions it seems as if there are thousands and thousands of exceptions all rooted to System.Net.Connection which are all stuck waiting to be finalized. They can't execute their finalize method because of the blocked finalizer thread below.

It's stuck on a Wait call which is part of the Dispose() method. I would recommend disposing ALL instances of the Chakra engine in your code as this will explicitly avoid the finalizer from being called. What the ChakraEngine looks like it's doing here is when this object is finalized it called a native method to reduce a ref counter to an object, this is either taking too long or never returns (I can't tell).

            Assuming you're using this library here (https://github.com/Taritsyn/MsieJavaScriptEngine), I would take a look at this code to ensure you know what it's doing when, as there are a lot of finalizers due to the PInvokes into the JavaScript engine. I think it's also pretty clear that this isn't a Microsoft library so I don't know how far Michael or I can help debug this._

Here is what is it waiting on.
[[HelperMethodFrame_1OBJ] (System.Threading.WaitHandle.WaitOneNative)] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean)

mscorlib_ni!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean)+1b
mscorlib_ni!System.Threading.WaitHandle.WaitOne(Int32, Boolean)+2e
MsieJavaScriptEngine.ScriptDispatcher.InnnerInvoke(System.Func`1)+80
MsieJavaScriptEngine.JsRt.Edge.ChakraEdgeJsRtJsEngine.Dispose(Boolean)+58
MsieJavaScriptEngine.JsRt.Edge.ChakraEdgeJsRtJsEngine.Finalize()+d
[[DebuggerU2MCatchHandlerFrame]]
[[ContextTransitionFrame]]
[[GCFrame]]
[[DebuggerU2MCatchHandlerFrame]]

Do you know if this is fixed in your latest release?

Do you know if this is fixed in your latest release?

What version of the MSIE JavaScript Engine are you using? Do you use this library as part of some other product?

We are currently using 2.2.7. I downloaded the code and made this change and it seems that the finalizer is no longer being blocked. Removed the invoke.

ChakraEdgeJsRtJsEngine.cs:
protected override void Dispose(bool disposing)
{
try
{
if (_disposedFlag.Set())
{
if (_dispatcher != null)
{
if (_jsContext.IsValid)
{
_jsContext.Release();
}

                    _jsRuntime.Dispose();
                    _dispatcher.Dispose();
                }
                base.Dispose(disposing);
            }
        }
        catch (Exception e)
        {
            base.Dispose(disposing);
        }
    }

Why do you use the following construction?

try
{}
catch (Exception e)
{
	base.Dispose(disposing);
}

I have always been in the habit of making sure that finalizer methods handle all exceptions.
I noticed that the Release method has:
EdgeJsErrorHelpers.ThrowIfError(EdgeNativeMethods.JsContextRelease(this, out count));

Perhaps this is extraneous though?

Perhaps this is extraneous though?

Yes, it is extraneous!

At the weekend, I will try to assess all the risks, that may be caused by the removal of _dispatcher.Invoke.

Much appreciated!

Try to upgrade to version 2.2.8.

Awesome, thanks for the quick fix!