我基于 LLBLGen 的大型 32 位 Web 服务数据访问应用程序单独运行在专用的 64 位机器上。当进程释放几乎所有分配的空间(高达 1.5GB)时,它的物理内存消耗稳步增长到大约 2GB,并从那时起继续增长。页面输入值或其他页面文件使用参数没有明显增加,因此看起来内存被释放而不是被换出到页面文件。我在想这是什么类型的个人资料?没有什么可以真正阻止进程获取它可以获取的所有内存,另一方面,内存释放存在不可接受的 http 内部错误 - 可能是清理块有用的工作。什么是使清理不那么突兀的好策略,
8 回答
听起来您有内存泄漏,该进程一直在泄漏内存,直到它因内存不足而崩溃,然后由服务器自动重新启动。
1.5GB 大约是 32 位进程在地址空间用完之前可以分配的最大内存量。
要寻找的东西:
- 你自己做缓存吗?什么时候从缓存中删除项目?
- 是否有某个地方每隔一段时间就会将数据添加到集合中但从未删除?
- 您是否在每个实现 IDisposable 的对象上调用 Dispose?
- 您是否访问任何非托管代码(COM 对象或使用 DllImport)或分配非托管内存(例如使用 Marshal 类)?垃圾收集器永远不会释放在那里分配的任何东西,您必须自己释放它。
- 您是否使用第 3 方库或来自第 3 方的任何代码?它也可能存在列表中的任何问题。
您是否有可能不处理各种一次性物品(特别是与数据库相关的)。这将使它们离开,可能会占用大量非托管资源,直到 GC 运行并调用它们的终结器。
值得对您的进程运行 perfmon 并查看某些关键资源(如句柄)是否稳定增长,或者您的数据库提供程序是否公开了性能计数器,然后是连接或打开的结果集。
我同意 edg 回答的第一部分,但他说:
“通过在对象死亡时将对象设置为 null,您可以鼓励 GC 重用这些对象消耗的内存,这限制了内存消耗的增长。”
是不正确的。您永远不需要将对象设置为 null,因为 GC 最终会在超出范围后收集您的对象。
在这个答案中对此进行了讨论:在 .NET 中使用后将对象设置为 Null/Nothing
不要使用 Arraylists(垃圾收集对它们不起作用),而是使用通用列表
其他常见错误是在 web.config 中 Debug=true,这会消耗大量内存,请将选项更改为“false”。
其他要做的事情是使用 CLRProfiler 来跟踪问题。
祝你好运,佩德罗
垃圾收集器在释放对象时不会自动释放内存,它会保留该内存以帮助最大限度地减少未来 malloc 的开销。
当触发内存不足的情况时,内存将返回给操作系统,并且在查看任务管理器时您将看到更多可用内存。这通常会发生在 2GB 标记或 3GB 如果您使用相关开关。
<contentious>
通过在对象死亡时将它们设置为 null,您可以鼓励 GC 重用这些对象消耗的内存,这限制了不断增长的内存消耗。
但是您应该将哪些对象设置为空?大对象、大集合、频繁创建的对象。
</contentious>
编辑:有证据支持将对象设置为 null 的值。有关详细信息,请参阅此。当然不需要将对象设置为null,关键是它对内存管理有什么帮助吗?
编辑:如果存在这样的事情而不是继续发表意见,我们需要一个最近的基准。
My first guess would be a memory leak. My second guess would be that it is normal behavior - the GC won't be fired until you have significant memory pressure. The only way to be sure is to use a combination of a profiler and things like PerfMon. Some sites:
- http://blogs.msdn.com/ricom/archive/2004/12/10/279612.aspx
- http://support.microsoft.com/kb/318263
- Tess's excellent lab series
In addition I would make sure you aren't running in Debug mode (as already mentioned).
As far as the HTTP errors - assuming you are running in server GC mode, it tries to do everything it can to not block requests. It would be interesting to find out what those HTTP errors are - that's not normal behavior from what I've seen in the past, and might point to some more of the root of your issue.
确保您没有建立项目的调试版本。有一个特性*,当您进行调试构建时,如果您实例化任何包含事件定义的对象,即使您不引发事件,它也只会无限期地保留一小块内存。随着时间的推移,这些小块内存会吞噬你的内存池,直到它最终重新启动 Web 进程并重新开始。
*我将此称为功能(而不是错误),因为它从 .Net 2 开始就存在(在 .Net 1.1 中不存在),并且没有修复它的补丁。内存泄漏一定是由于调试时需要的某些功能。
我们遇到了类似的情况,并更改了我们所有的数据库连接以使用 try/catch/finally 方法。Try 用于执行代码,捕获错误收集,最后关闭所有变量和数据库连接。
internal BECollection<ReportEntity> GetSomeReport()
{
Database db = DatabaseFactory.CreateDatabase();
BECollection<ReportEntity> _ind = new BECollection<ReportEntity>();
System.Data.Common.DbCommand dbc = db.GetStoredProcCommand("storedprocedure");
try
{
SqlDataReader reader = (SqlDataReader)db.ExecuteReader(dbc);
while (reader.Read())
{
//populate entity
}
}
catch (Exception ex)
{
Logging.LogMe(ex.Message.ToString(), "Error on SomeLayer/SomeReport", 1, 1);
return null;
}
finally
{
dbc.Connection.Close();
_ind = null;
}
return _ind;
}