问题
I'm new to Ninject, but I've become convinced that the out of the box configuration for Ninject.MVC5 NuGet package never actually releases the objects scoped to the HttpContext. I consistently get an OutOfMemoryException after a bout of repeated heavy memory usage by some of my larger reports.
So to prove I wasn't losing my mind I created an empty test project. I created a default project in VS 2017 by File -> New Project -> C# -> Web -> ASP.NET Web Application -> MVC (in the modal). This is a new solution too, to be clear. I then installed Ninject 3.2.2 (not the latest; <3.3 is required for Ninject.MVC5), then installed Ninject.MVC5.
Then I went to HomeController.cs and first added a class to the bottom of the file:
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;
}
}
Then I added a constructor to HomeController:
public class HomeController : Controller
{
readonly MemoryEater _me;
public HomeController(MemoryEater me)
{
_me = me;
}
And finally I opened up NinjectWebCommon.cs, which I didn't modify in any way up until now (this file created 100% by installing Ninject.MVC5 via NuGet), and added one line to RegisterServices:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<MemoryEater>().ToSelf().InRequestScope();
}
I then run the app with IISExpress and viewed in Chrome (on Windows 10). I refresh the page and watch the memory usage climb; some GCs happen clearly as the memory usage drops, which is expected b/c the List object has to grow. But it keeps climbing past 600MB and, after a few dozen refreshes, I get an OutOfMemoryException in my app.
So I went a step further and copied the source from GitHub for OnePerRequestHttpModule.cs into a new file in my project, and split up the method DeactivateInstancesForCurrentHttpRequest so that I could put a breakpoint where ICache.Clear is called:
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
}
I changed NinjectWebCommon to use my new copy of OnePerRequestHttpModule and put breakpoints at A and B. After every request A is called but B is never called.
Am I doing something wrong or is this a legit bug? It seems unthinkable to me that this bug could exist and me, a n00b to Ninject, could be the first one to find it.
回答1:
Have a closer look at the version of your Ninject.Web.Common nuget package.
If it is less than 3.2.2, this is the cause of your issue.
This bug has been fixed in version 3.2.2
来源:https://stackoverflow.com/questions/46839779/ninject-mvc5-release-scope-never-called-outofmemoryexception