本文介绍在Microsoft ASP.NET 中遇到高内存时要检查的快速事项。
原始产品版本: ASP.NET
原始 KB 编号: 893660
本文将首先介绍一些常见问题、解决这些问题的作,以及导致这些问题的原因的简要说明。
ASP.NET 支持语音列
在 2005 年 4 月的支持语音列中,我们无意中提供了指向错误文件的链接。 我们不会链接到 Web 服务的下载,而是链接到 Web 服务返回的 XML 文件。 已更正该链接。 如果要查看附加了正确文件的文章,请参阅 使用 XMLHTTP 的动态页面更新。
被视为高内存的内容
显然,此问题取决于特定应用程序的卷和活动。 通常,高内存是在 ASP.NET 工作进程(Aspnet_wp.exe)或 Internet Information Services(IIS)工作进程(W3wp.exe)内存持续增加且不会恢复到舒适级别时。
一般情况下,默认 2 GB 用户内存地址空间中的舒适级别将低于 600 MB。 内存级别高于该舒适级别后,我们做的比应该少。 此行为可能会影响系统上运行的其他应用程序。
关键是了解某些应用程序需要比其他应用程序更多的内存。 如果超出这些限制,可以添加更多内存或将另一台服务器添加到 Web 场(或考虑 Web 场)。 在这些情况下,还建议分析。 它使开发人员能够创建更精简的应用程序。 在本文中,我们将探讨一种情况,即在服务器停止执行之前,你一直看到内存上升。
为调试设置的应用程序
我们在此支持中看到的高内存的一个原因是你为应用程序启用了调试、跟踪或两者。 开发应用程序时,必须启用调试和跟踪。 默认情况下,在 Visual Studio .NET 中创建应用程序时,会在 Web.config 文件中看到以下属性集:
<compilation
...
debug="true"
/>
或
<trace
enabled="true"
...
/>
此外,执行应用程序的最终生成时,请确保在发布模式下执行此作,而不是调试模式。 进入生产环境后,不应再进行调试。 它确实会降低性能并消耗内存。 设置此属性意味着更改了处理应用程序的方式的一些事项。
首先,即使此元素中 compilation
设置了批处理编译,也会禁用批处理编译。 这意味着为应用程序中的每一页创建一个程序集,以便可以将其分解。 这些程序集可以随机分散在内存空间中,从而更难找到连续空间来分配内存。
其次,属性 executionTimeout
(<httpRuntime> 元素)设置为高数字,替代默认值 90 秒。 调试时,这很好,因为在耐心地单步执行代码以查找错误时,应用程序无法超时。 但是,生产中存在重大风险。 这意味着,如果你有流氓请求,无论出于什么原因,它将坚持线程,并继续任何有害行为几天,而不是几分钟。
最后,你将在 临时 ASP.NET 文件夹中创建更多文件。
System.Diagnostics.DebuggableAttribute
并且(System.Diagnostics 命名空间将添加到所有生成的代码中,这可能会导致性能下降。
如果你从本文中没有其他内容,我希望你获得此信息。 启用调试是错误的。 我们经常看到这种行为,很容易更改。 请记住,可以在页面级别设置它。 确保所有页面未设置。
字符串串联
有些应用程序使用服务器端代码生成 HTML 输出,而只需生成一个大型 HTML 字符串即可发送到浏览器。 这很好,但如果使用 +
和 &
串联来生成字符串,则可能不知道要生成的大型字符串数。 例如:
string mystring = "<html>";
mystring = mystring + "<table><tr><td>";
mystring = mystring + "First Cell";
mystring = mystring + "</td></tr></table>";
mystring = mystring + "</html>";
此代码似乎足够无害,但内存中存储的内容如下:
<html>
<html><table><tr><td>
<html><table><tr><td>First Cell
<html><table><tr><td>First Cell</td></tr></table>
<html><table><tr><td>First Cell</td></tr></table></html>
你可能认为你只是存储最后一行,但你正在存储 所有这些 行。 你可以看到它如何失控,尤其是在构建大型表时,也许通过循环访问大型记录集。 如果是要执行的作,请使用我们的 System.Text.StringBuilder
类,以便只存储一个大字符串。 请参阅 使用 Visual C# 提高字符串串联性能
.NET Framework Service Pack 1 (SP1)
如果尚未运行 .NET Framework SP1,请安装此 SP(如果遇到内存问题)。 我不会详细介绍,但基本上,使用 SP1,我们现在以更高效的方式分配内存。 基本上,我们一次为大型对象分配 16 MB,而不是一次分配 64 MB。 我们都移动了,我们都知道,如果我们使用许多小箱子而不是几个大箱子,我们可以把更多的包装成汽车或卡车。 这是这个想法。
不要害怕定期回收
默认情况下,我们每隔 29 小时在 IIS 中回收应用程序池。 Aspnet_wp.exe进程将一直持续到你结束任务、重启 IIS 或重新启动计算机。 此行为意味着此过程可以运行数月。 对于某些应用程序来说,最好每隔几天左右在方便的时候重启工作进程。
应考虑的问题
前面的所有作都可以快速修复。 但是,如果遇到内存问题,请问自己以下问题:
我使用的是许多大型对象吗? 超过 85,000 KB 存储在大型对象堆中。
是否在会话状态中存储对象? 这些对象将保留在内存中的时间比使用和释放它们的时间要长得多。
我使用的是对象
Cache
吗? 明智地使用它时,性能是一个很好的好处。 但是,当它被不明智地使用时,你最终会用到大量的内存,从来没有释放过。是否为 Web 应用程序返回
recordsets
太大? 没有人希望在网页上查看 1,000 条记录。 应设计应用程序,以便一次行程中永远不会获得超过 50 到 100 条记录。
调试
我不会开始设置 WinDbg。 但是,如果想要排查更复杂的问题,可以使用以下命令查看内存中的确切内容。
!eeheap -gc
此命令将显示你拥有多少托管内存。 如果此值很高,则托管代码正在生成。
!dumpheap -stat
此命令需要相当长的时间才能运行,即使内存很大,也会花费数小时。 但此命令将为你提供所有对象的列表、每种类型的数量以及每个类型的内存量。 (例如,对于 StringBuilder
类,你将看到许多 System.String
对象)
发现对象占用大量内存后,请使用以下命令进一步挖掘:
!do <addr>
可以在命令中 dumpheap
获取要查找的对象地址。
我们将尝试将更多方法用于在这些列中的特定情况下使用此诊断工具。 如果我们做得不错,请告诉我们!