2016-05-23 10 views
4

Ich habe ein einfaches ASP.NET 5-Standardprojekt erstellt. Ich habe einen Controller, der erstelltnicht genügend Arbeitsspeicher, wenn Clearscript V8-Engine wiederholt initialisiert wird (GC-Problem?)

und gibt einige Mock Json. Wenn ich Seite gewisse Zeiten aktualisieren erhalte ich

Fatal error in Haufen Setup

Allocation fehlgeschlagen - Prozess aus dem Speicher

Und folgenden Stack-Trace

Unhandled Exception: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 
    at V8Isolate.Create(StdString* , V8IsolateConstraints* , Boolean , Int32) 
    at Microsoft.ClearScript.V8.V8IsolateProxyImpl..ctor(String gcName, V8RuntimeConstraints gcConstraints, Boolean enableDebugging, Int32 debugPort) 
    --- End of inner exception stack trace --- 
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) 
    at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
    at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark) 
    at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) 
    at System.Activator.CreateInstance(Type type, Object[] args) 
    at Microsoft.ClearScript.V8.V8Proxy.CreateImpl[T](Object[] args) 
    at Microsoft.ClearScript.V8.V8IsolateProxy.Create(String name, V8RuntimeConstraints constraints, Boolean enableDebugging, Int32 debugPort) 
    at Microsoft.ClearScript.V8.V8Runtime..ctor(String name, V8RuntimeConstraints constraints, V8RuntimeFlags flags, Int32 debugPort) 
    at Microsoft.ClearScript.V8.V8ScriptEngine..ctor(V8Runtime runtime, String name, V8RuntimeConstraints constraints, V8ScriptEngineFlags flags, Int32 debugPort) 
    at Microsoft.ClearScript.V8.V8ScriptEngine..ctor() 

I versuchte, den Speicher mit dotMemory zu betrachten. Jedes Mal, wenn ich die Seite aktualisiere, wird eine Engine erstellt und fügt dem nicht verwalteten Speicher 2 MB RAM hinzu. Wenn es ein bestimmtes Limit erreicht, stürzt es wie oben beschrieben ab. Solange ich auf force GC klicke, bevor ich das Limit erreicht habe, geht der Speicher aus und ich kann die Seite erneut verwenden.

Meine Frage ist: Warum behandelt GC das überhaupt nicht? Nach jeder Anfrage kann das Objekt entsorgt werden, wenn ich GC erzwinge. Ich würde sagen, wenn ich fast keine Erinnerung mehr habe, aber ich kann es mit GC zurückfordern, würde es das tun.

Wie kann ich dieses Problem lösen? Vielleicht würde das Hinzufügen von mehr Speicher helfen, aber ich weiß auch nicht, wie ich das machen soll. Wenn GC diese Objekte niemals säubert, wird es trotzdem brechen.

Gleiches passiert, wenn ich Kestrel (dnx web) und mit IIS laufen lasse. Ich habe Rahmen auf "dnx46"

Hier ist meine dnx Version

$ dnx --version 
Microsoft .NET Execution environment 
Version:  1.0.0-rc1-16231 
Type:   Clr 
Architecture: x86 
OS Name:  Windows 
OS Version: 10.0 
Runtime Id: win10-x86 

ClearScript Version ist "ClearScript.V8": "5.4.3"

+0

nullen Sie alle Verweise darauf nach Gebrauch aus oder warten Sie, bis das Ende des Lebens entschieden ist? – BugFinder

+0

Ich mache es nicht ungültig, aber es geht aus dem Geltungsbereich: '[HttpGet] public JsonResult Get() {var engine = new V8ScriptEngine(); return new JsonResult ("asd"); } ' –

+0

Ive hatte Probleme, wo Dinge in den Out-Bereich gleiten ist nicht genug - Ive hatte es mit Excel, um den Punkt, auch wenn Sie sagen, beenden, würde es offen lassen .. Ich hatte es mit vielen Dingen, Nullen sie out hat das Problem immer behoben – BugFinder

Antwort

6

Die kurze Version: Sie müssen jede Script-Engine zu dispose, wenn Sie fertig sind mit es. Ein bequemer Weg ist es, die using Anweisung:

using (var engine = new V8ScriptEngine()) { 
    // do stuff 
} 

Längere Version: Jede V8-Instanz einen großen Block von Adressraum vorbehält. Diese werden nicht als belegter Speicher angezeigt, aber in einem 32-Bit-Prozess kann der Adressraum mit nur wenigen Dutzend Instanzen erschöpft sein. Der verwaltete GC würde schließlich alles aufräumen, aber weil er die Adressraumreservierungen von V8 nicht verfolgen kann, hat er es nicht eilig, da er keinen Speicherdruck erkennt. Schließlich kommen Sie zu einem Punkt, wo Ihr Speicher Verbrauch immer noch niedrig ist, aber V8 kann nicht mehr einen großen Block von Adressraum reservieren, und so schlägt es fehl.

+0

Also wenn ich eine Klasse habe, die die Engine intern erzeugt, sollte ich 'IDisposable' darin implementieren und an 'Dispose'-Methode der Engine delegieren und sie explizit aufrufen, wenn ich fertig bin oder' using' verwende Konstruieren, oder? –

+0

Nun, ich habe das versucht und funktioniert wie ein Zauber! –

+0

Ja; Wenn Ihre Klasse 'V8ScriptEngine' intern verwendet, sollte für beste Ergebnisse 'IDisposable' implementiert und die Implementierung delegiert werden. – BitCortex