【问题标题】:How do I properly dispose and free the memory used for V8.Net.V8Engine instances?如何正确处置和释放用于 V8.Net.V8Engine 实例的内存?
【发布时间】:2015-12-07 13:22:35
【问题描述】:

我在使用我的 V8Engine 实例时遇到了一个问题,它似乎有一个小的内存泄漏,并且处理它,以及强制垃圾收集似乎没有多大帮助。它最终会在 V8Enging local_m_negine = new V8Engine() 上抛出 AccessViolationException 并声明 Fatal error in heap setup, Allocation failed - process out of memoryAttempted to read or write protected memory. This is often an indication that other memory is corrupt.

在运行时通过任务管理器监控程序的内存使用情况确认它正在泄漏内存,我认为每两秒钟大约 1000 KB。我怀疑是在执行脚本中声明的变量没有被收集,或者与GlobalObject.SetProperty 方法有关。调用V8Engine.ForceV8GarbageCollection()V8Engine.Dispose() 甚至GC.WaitForPendingFinalizers()GC.Collect() 并不能防止内存泄漏(尽管值得注意的是,使用这些命令似乎会更慢地泄漏它,我知道我应该'不使用 GC,但它是最后的手段,看看它是否能解决问题。)

也可以提供解决方案的一个切线问题是无法清除 V8Engine 的执行上下文。我需要为每个脚本处理和重新实例化引擎,我认为这是发生内存泄漏的地方,否则我会遇到已经声明变量的问题,导致V8Engine.Execute() 抛出异常说这样。

我可以肯定地确认内存泄漏与 V8Engine 实现有关,因为运行该程序的旧版本使用 Microsoft.JScript 没有这种内存泄漏,并且使用的内存保持一致。

受影响的代码如下;

//Create the V8Engine and dispose when done
using (V8Engine 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);

    //Please just clear everything I can't cope.
    local_m_engine.ForceV8GarbageCollection();
    local_m_engine.GlobalObject.Dispose();
}

编辑:

不确定这会有多大用处,但我一直在上面运行一些内存分析工具,并且了解到在运行原始代码的隔离版本后,我的软件最终会出现大量 IndexedObjectList 的实例空值(参见此处:http://imgur.com/a/bll5K)。对于每个生成的 V8Engine 实例,似乎每个类都有一个实例,但它们没有被释放或释放。我不禁觉得我在这里缺少命令或其他东西。 我用来测试和重新创建上述实现导致的内存泄漏的代码如下:

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;

            }
        }
    }
}

【问题讨论】:

  • '我可以肯定地确认内存泄漏与 V8 实现有关',也许您应该提供 那个 代码。如果你分配一个对象而不释放它,它的内存将不会被释放。不管你强制垃圾回收多少次。
  • @SteveWellens 我已经为 V8Engine 提供了代码......using 命令将在最后自动调用对象的Dispose 函数,并且这个 C# 具有本机垃圾收集,它将释放未使用、被覆盖或超出范围变量的内存。如果您希望我提供任何其他代码,请告诉我,但提供的代码显示了 V8Engine 的实例化以及对它的所有引用。这个问题是在询问是否有人知道如何正确处理 V8Engine 以防止这种内存泄漏,因为显然正常的 Dispose 是不够的。
  • @SteveWellens 我没有从 V8 实例化任何其他东西,只是 V8Engine。我将编辑我的帖子以澄清我的意思是内存泄漏与 V8Engine 实现有关
  • WeakReference 是我要说的确凿证据。任何使用它们来跟踪 GC 对象但在其 IsAlive 属性返回 false 时不会再次删除它们的 .NET 代码都存在内存泄漏。很常见的错误。您必须深入研究 .NET 包装器代码并了解清理工作是如何完成的。
  • @HansPassant 谢谢汉斯!我现在正在查看源代码,看看是否有什么突出的地方,也在等待其背后的开发人员的回复

标签: c# .net memory memory-leaks v8.net


【解决方案1】:

抱歉,我不知道存在这个问题。确保使用v8.net 标签。

你的问题是这一行:

result = local_m_engine.Execute(script);

返回的结果永远不会被释放。 ;) 您对退回的句柄负责。这些句柄是结构值,而不是类对象。

你也可以using (result = local_m_engine.Execute(script)) { ... }

有一个new version released。我终于再次复活了这个项目,因为我将需要它用于 FlowScript VPL 项目 - 它现在支持 .Net Standard 以及跨平台支持!

【讨论】:

    猜你喜欢
    • 2013-02-23
    • 1970-01-01
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2016-08-09
    相关资源
    最近更新 更多