ASP.NET 个应用程序的高内存使用率
High memory usage by ASP.NET applications
我们的一些 ASP.Net 应用程序存在问题。我们的一些应用程序从一开始就要求大量内存作为它们的工作集。
在我们的 2 个 webfarm-servers(每个 4gb RAM)上 运行 多个应用程序。我们有一个稳定的环境,大约有 1.2gb 的可用内存。
然后我们添加一个 MVC5 + WebApi v2 + Entity Framework 应用程序,它立即声称 1+gb 作为工作集内存,而实际上只使用了大约 300mb。这会导致其他应用程序抱怨没有足够的剩余内存。
我们已经尝试设置虚拟内存限制和私有内存限制,但没有任何效果。如果我们将其设置为大约 500mb,应用程序仍会使用或多或少相同的内存量(超过 500)并且似乎不遵守规定的限制。
作为参考,我用一个空的 MVC5 项目(VS2013 模板)对此进行了测试,这已经占用了 300mb 的内存,而只使用了大约 10mb。
将应用设置为 32 位应用似乎对减小工作集的大小有一些影响。
有什么方法可以减少工作集的大小,或者对其大小施加硬性限制吗?
编辑:
在使用 Web Api v2 和 Entity Framework 的项目使用大量内存的情况下,我的 API 控制器如下所示:
namespace Foo.Api
{
public class BarController : ApiController
{
private FooContext db = new FooContext();
public IQueryable<Bar> GetBar(string bla)
{
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
}
}
在我能找到的大多数教程(包括来自微软的教程)中都是如此。由于 LINQ 延迟加载,此处使用 using
不起作用。如果我在所有地方添加一个 ToList(未测试),它可能会起作用,但这是否有任何其他影响?
编辑2:
如果我这样做就有效
namespace Foo.Api
{
public class BarController : ApiController
{
public List<Bar> GetBar(string bla)
{
using(FooContext db = new FooContext){
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year).ToList();
}
}
}
ToList() 对 api 的性能有任何影响吗? (我知道我不能像使用 IQueryable 那样继续廉价查询)
编辑3:
我注意到它的应用程序的私有工作集非常高。有没有办法限制这个? (不会造成不断的回收)
编辑4:
据我所知,我在每个 API 控制器上都有一个 Dispose。我的前端只是一些简单的 MVC 控制器,但大部分是 .cshtml 和 javascript (angular) 文件。
我们有另一个应用程序,只是普通的 mvc,有两个模型和一些简单的视图(没有数据库,或其他可能泄漏的外部资源),这也消耗高达 4-500mb 的内存。如果我分析它,我看不到任何表明内存泄漏的东西,我确实看到实际只使用了 10 或 20 mb,其余是未分配的非托管内存(但私有内存工作集的一部分,因此由此应用程序且无法被任何其他应用程序使用)。
我的一些应用程序也遇到了类似的问题。通过将一次性数据库资源包装在 using 子句中,我能够通过正确关闭一次性数据库资源来解决问题。
对于 Entity Framework,这意味着确保您始终在每次请求后关闭上下文。应在请求之间处理连接。
using (var db = new MyEFContext())
{
// Execute queries here
var query = from u as db.User
where u.UserId = 1234
select u.Name;
// Execute the query.
return query.ToList();
// This bracket will dispose the context properly.
}
您可能需要将上下文包装到一个请求缓存您的上下文的服务中,以便在整个请求过程中保持其活动状态,并在完成后将其丢弃。
或者,如果使用为整个控制器提供单一上下文的模式 like in the MSDN examples, make sure you override the Dispose(bool)
method, like the example here。
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
所以你的控制器(从上面看)应该是这样的:
namespace Foo.Api
{
public class BarController : ApiController
{
private FooContext db = new FooContext();
public IQueryable<Bar> GetBar(string bla)
{
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
}
// WebApi 2 will call this automatically after each
// request. You need this to ensure your context is disposed
// and the memory it is using is freed when your app does garbage
// collection.
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
我看到的行为是应用程序会消耗大量内存,但它可以垃圾收集足够的内存以防止它获得 OutOfMemoryException
。这使得问题很难找到,但是配置数据库资源解决了它。其中一个应用程序的 RAM 使用量曾经徘徊在 600 MB 左右,现在徘徊在 75 MB 左右。
但是这个建议不仅仅适用于数据库连接。 任何 class 实现 IDisposable
如果你 运行 进入内存泄漏,应该怀疑。但是既然你提到你正在使用 EntityFramework,那么它很可能是可疑的。
删除所有 Telerik Kendo MVC 引用(dll 等)解决了我们的问题。如果我们 运行 没有应用程序,我们所有的内存问题都会消失,我们会看到正常的内存使用。
基本上:这是一个导致高内存使用的外部库。
我们的一些 ASP.Net 应用程序存在问题。我们的一些应用程序从一开始就要求大量内存作为它们的工作集。
在我们的 2 个 webfarm-servers(每个 4gb RAM)上 运行 多个应用程序。我们有一个稳定的环境,大约有 1.2gb 的可用内存。
然后我们添加一个 MVC5 + WebApi v2 + Entity Framework 应用程序,它立即声称 1+gb 作为工作集内存,而实际上只使用了大约 300mb。这会导致其他应用程序抱怨没有足够的剩余内存。
我们已经尝试设置虚拟内存限制和私有内存限制,但没有任何效果。如果我们将其设置为大约 500mb,应用程序仍会使用或多或少相同的内存量(超过 500)并且似乎不遵守规定的限制。
作为参考,我用一个空的 MVC5 项目(VS2013 模板)对此进行了测试,这已经占用了 300mb 的内存,而只使用了大约 10mb。
将应用设置为 32 位应用似乎对减小工作集的大小有一些影响。
有什么方法可以减少工作集的大小,或者对其大小施加硬性限制吗?
编辑: 在使用 Web Api v2 和 Entity Framework 的项目使用大量内存的情况下,我的 API 控制器如下所示:
namespace Foo.Api
{
public class BarController : ApiController
{
private FooContext db = new FooContext();
public IQueryable<Bar> GetBar(string bla)
{
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
}
}
在我能找到的大多数教程(包括来自微软的教程)中都是如此。由于 LINQ 延迟加载,此处使用 using
不起作用。如果我在所有地方添加一个 ToList(未测试),它可能会起作用,但这是否有任何其他影响?
编辑2: 如果我这样做就有效
namespace Foo.Api
{
public class BarController : ApiController
{
public List<Bar> GetBar(string bla)
{
using(FooContext db = new FooContext){
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year).ToList();
}
}
}
ToList() 对 api 的性能有任何影响吗? (我知道我不能像使用 IQueryable 那样继续廉价查询)
编辑3: 我注意到它的应用程序的私有工作集非常高。有没有办法限制这个? (不会造成不断的回收)
编辑4: 据我所知,我在每个 API 控制器上都有一个 Dispose。我的前端只是一些简单的 MVC 控制器,但大部分是 .cshtml 和 javascript (angular) 文件。
我们有另一个应用程序,只是普通的 mvc,有两个模型和一些简单的视图(没有数据库,或其他可能泄漏的外部资源),这也消耗高达 4-500mb 的内存。如果我分析它,我看不到任何表明内存泄漏的东西,我确实看到实际只使用了 10 或 20 mb,其余是未分配的非托管内存(但私有内存工作集的一部分,因此由此应用程序且无法被任何其他应用程序使用)。
我的一些应用程序也遇到了类似的问题。通过将一次性数据库资源包装在 using 子句中,我能够通过正确关闭一次性数据库资源来解决问题。
对于 Entity Framework,这意味着确保您始终在每次请求后关闭上下文。应在请求之间处理连接。
using (var db = new MyEFContext())
{
// Execute queries here
var query = from u as db.User
where u.UserId = 1234
select u.Name;
// Execute the query.
return query.ToList();
// This bracket will dispose the context properly.
}
您可能需要将上下文包装到一个请求缓存您的上下文的服务中,以便在整个请求过程中保持其活动状态,并在完成后将其丢弃。
或者,如果使用为整个控制器提供单一上下文的模式 like in the MSDN examples, make sure you override the Dispose(bool)
method, like the example here。
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
所以你的控制器(从上面看)应该是这样的:
namespace Foo.Api
{
public class BarController : ApiController
{
private FooContext db = new FooContext();
public IQueryable<Bar> GetBar(string bla)
{
return db.Bar.Where(f => f.Category.Equals(bla)).OrderBy(f => f.Year);
}
// WebApi 2 will call this automatically after each
// request. You need this to ensure your context is disposed
// and the memory it is using is freed when your app does garbage
// collection.
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
我看到的行为是应用程序会消耗大量内存,但它可以垃圾收集足够的内存以防止它获得 OutOfMemoryException
。这使得问题很难找到,但是配置数据库资源解决了它。其中一个应用程序的 RAM 使用量曾经徘徊在 600 MB 左右,现在徘徊在 75 MB 左右。
但是这个建议不仅仅适用于数据库连接。 任何 class 实现 IDisposable
如果你 运行 进入内存泄漏,应该怀疑。但是既然你提到你正在使用 EntityFramework,那么它很可能是可疑的。
删除所有 Telerik Kendo MVC 引用(dll 等)解决了我们的问题。如果我们 运行 没有应用程序,我们所有的内存问题都会消失,我们会看到正常的内存使用。
基本上:这是一个导致高内存使用的外部库。