Ninject.MVC5 发布范围从未调用 - OutOfMemoryException
Ninject.MVC5 Release Scope Never Called - OutOfMemoryException
我是 Ninject 的新手,但我确信 Ninject.MVC5 NuGet 包的开箱即用配置从未真正释放作用域为 HttpContext 的对象。在我的一些较大的报告反复大量使用内存后,我总是得到 OutOfMemoryException。
因此,为了证明我没有失去理智,我创建了一个空的测试项目。我通过 File -> New Project -> C# -> Web -> ASP.NET Web Application -> MVC(在模式中)在 VS 2017 中创建了一个默认项目。需要明确的是,这也是一个新的解决方案。然后我安装了 Ninject 3.2.2(不是最新的;<3.3 是 Ninject.MVC5 所必需的),然后安装了 Ninject.MVC5.
然后我去HomeController.cs,先在文件底部加了一个class:
public class MemoryEater : IDisposable
{
public List<int> _nums = new List<int>();
public MemoryEater()
{
var rand = new Random(); // Use random so that I get a bit of CPU usage I can see in Task Manager
for (int cnt = 0; cnt < 2_500_000; ++cnt)
{
var key = rand.Next();
_nums.Add(key);
}
}
public void Dispose()
{
if (_nums != null)
_nums = null;
}
}
然后我给HomeController添加了一个构造函数:
public class HomeController : Controller
{
readonly MemoryEater _me;
public HomeController(MemoryEater me)
{
_me = me;
}
最后我打开了 NinjectWebCommon.cs,直到现在我都没有对它进行任何修改(这个文件是通过 NuGet 安装 Ninject.MVC5 创建的 100%),并添加了一个RegisterServices 行:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<MemoryEater>().ToSelf().InRequestScope();
}
然后我 运行 使用 IISExpress 的应用程序并在 Chrome 中查看(在 Windows 10)。我刷新页面并观察内存使用量攀升;随着内存使用量的下降,一些 GC 明显发生,这是预期的 b/c List 对象必须增长。但它不断攀升超过 600MB,并且在刷新几十次后,我的应用程序出现了 OutOfMemoryException。
所以我更进一步,将 GitHub 中 OnePerRequestHttpModule.cs 的源代码复制到我项目中的一个新文件中,并将方法 DeactivateInstancesForCurrentHttpRequest 分开,这样我就可以在 ICache.Clear 被称为:
public void DeactivateInstancesForCurrentHttpRequest()
{
if (this.ReleaseScopeAtRequestEnd)
{
var context = HttpContext.Current;
this.MapKernels(kernel => ClearCacheOfContext(kernel, context)); // BREAKPOINT A
}
}
private void ClearCacheOfContext(IKernel kernel, HttpContext context)
{
kernel.Components.Get<ICache>().Clear(context); // BREAKPOINT B
}
我更改了 NinjectWebCommon 以使用我的 OnePerRequestHttpModule 的新副本,并在 A 和 B 处放置了断点。在每个请求 A 被调用之后,但 B 从未被调用。
我是不是做错了什么或者这是一个合法的错误?对我来说,这个错误可能存在似乎是不可想象的,而我,一个 Ninject 的 n00b,可能是第一个发现它的人。
仔细查看 Ninject.Web.Common nuget 包的版本。
如果低于 3.2.2,这就是您问题的原因。
我是 Ninject 的新手,但我确信 Ninject.MVC5 NuGet 包的开箱即用配置从未真正释放作用域为 HttpContext 的对象。在我的一些较大的报告反复大量使用内存后,我总是得到 OutOfMemoryException。
因此,为了证明我没有失去理智,我创建了一个空的测试项目。我通过 File -> New Project -> C# -> Web -> ASP.NET Web Application -> MVC(在模式中)在 VS 2017 中创建了一个默认项目。需要明确的是,这也是一个新的解决方案。然后我安装了 Ninject 3.2.2(不是最新的;<3.3 是 Ninject.MVC5 所必需的),然后安装了 Ninject.MVC5.
然后我去HomeController.cs,先在文件底部加了一个class:
public class MemoryEater : IDisposable
{
public List<int> _nums = new List<int>();
public MemoryEater()
{
var rand = new Random(); // Use random so that I get a bit of CPU usage I can see in Task Manager
for (int cnt = 0; cnt < 2_500_000; ++cnt)
{
var key = rand.Next();
_nums.Add(key);
}
}
public void Dispose()
{
if (_nums != null)
_nums = null;
}
}
然后我给HomeController添加了一个构造函数:
public class HomeController : Controller
{
readonly MemoryEater _me;
public HomeController(MemoryEater me)
{
_me = me;
}
最后我打开了 NinjectWebCommon.cs,直到现在我都没有对它进行任何修改(这个文件是通过 NuGet 安装 Ninject.MVC5 创建的 100%),并添加了一个RegisterServices 行:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<MemoryEater>().ToSelf().InRequestScope();
}
然后我 运行 使用 IISExpress 的应用程序并在 Chrome 中查看(在 Windows 10)。我刷新页面并观察内存使用量攀升;随着内存使用量的下降,一些 GC 明显发生,这是预期的 b/c List 对象必须增长。但它不断攀升超过 600MB,并且在刷新几十次后,我的应用程序出现了 OutOfMemoryException。
所以我更进一步,将 GitHub 中 OnePerRequestHttpModule.cs 的源代码复制到我项目中的一个新文件中,并将方法 DeactivateInstancesForCurrentHttpRequest 分开,这样我就可以在 ICache.Clear 被称为:
public void DeactivateInstancesForCurrentHttpRequest()
{
if (this.ReleaseScopeAtRequestEnd)
{
var context = HttpContext.Current;
this.MapKernels(kernel => ClearCacheOfContext(kernel, context)); // BREAKPOINT A
}
}
private void ClearCacheOfContext(IKernel kernel, HttpContext context)
{
kernel.Components.Get<ICache>().Clear(context); // BREAKPOINT B
}
我更改了 NinjectWebCommon 以使用我的 OnePerRequestHttpModule 的新副本,并在 A 和 B 处放置了断点。在每个请求 A 被调用之后,但 B 从未被调用。
我是不是做错了什么或者这是一个合法的错误?对我来说,这个错误可能存在似乎是不可想象的,而我,一个 Ninject 的 n00b,可能是第一个发现它的人。
仔细查看 Ninject.Web.Common nuget 包的版本。
如果低于 3.2.2,这就是您问题的原因。