找出内存泄漏

8
我有一个Web应用程序,使用了许多不同的第三方组件、CMS和我的代码。出现了内存不足异常。

脚本抛出异常:内存不足

我试图找出问题所在。这是我发现的情况:
  • 我使用50个线程运行测试,调用我的Web应用程序的15个页面。内存似乎没问题。IIS进程只使用了400 MB的RAM。

  • 我在web.config中添加了一个空格,然后我的IIS进程在30分钟内开始增长到超过1 GB。 Visual Studio无法对我的内存进行快照,因为它太大了(真的吗?!)。所以我安装了ANTS内存分析器,但它表示我的应用程序只使用了约300 MBANTS only 300 MB

IIS进程占用1 GB内存 [1]: https://i.stack.imgur.com/Ig8pY.png

测试几分钟后停止,但内存未被释放。

(ANTS分析器崩溃了,所以我重新启动了它) 释放后422MB IIS 1.2GB 摘要 4MB的字符串

似乎该应用程序并没有使用100-200MB的内存,尤其是我为我的控制器使用了输出缓存。我不明白的是,为什么IIS消耗的内存一直在增长,出了什么问题。
更新:
我的应用程序由于W3WP崩溃而自动重启,导致IIS释放内存,而我的压力测试已经运行了一段时间:

应用程序:w3wp.exe 框架版本:v4.0.30319 描述:该进程因.NET Runtime中IP 5A3A86F1(5A0F0000)的内部错误而终止,退出代码为80131506。


应用程序名称: w3wp.exe,版本: 10.0.15063.0,时间戳: 0xacce422f 故障模块名称: clr.dll,版本: 4.7.2098.0,时间戳: 0x59028d36 异常代码: 0xc0000005 故障偏移量: 0x002b86f1 故障进程 ID: 0x50a4 应用程序启动时间: 0x01d2ee688f323893 应用程序路径: C:\WINDOWS\SysWOW64\inetsrv\w3wp.exe 模块路径: C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll 报告 ID: 4362ddc5-f8d7-4441-8916-3830f9268b3a 故障包完整名称: 故障包相关应用程序 ID:

enter image description here

更新2

我运行了DebugDiag,并对该网站进行了压力测试,直到它消耗了约3.5 GB的内存。

enter image description here

Chakra是微软的一个库。

enter image description here enter image description here

所以现在我有两个问题。

  1. 是ChakraCore泄漏了还是使用/分配它的库泄漏了?如何定义哪个库?

2- 它说有27,000个分配。这是否意味着仍有27,000个在内存中,或者其中一些可能已被分配并处置?

3- 它仍然没有告诉我关于剩余的3GB消耗的RAM的任何信息。它只有总共600MB(私有+虚拟)。


1
你能给我们展示一下 Script threw an exception: Out of memory 的截图吗?我特别想知道它是在服务器端还是客户端出现的。 - mjwills
1
@mjwills 感谢你的回复。这是在 JavaScript 引擎切换器内部,但我没有堆栈跟踪,因为 reactjs.net 包装了异常 :| JavaScriptEngineSwitcher.Core.JsRuntimeException: Out of memory. 行: 0 列: 0 at React.ReactEnvironment.Execute[T](String code) - Ashkan S
2
使用Perfmon和DebugDiag的组合来定位IIS工作进程。如果您将这些工具结合使用,则应将您指向有问题的程序集。以下是逐步设置教程。祝你好运。https://learn.microsoft.com/en-us/iis/troubleshoot/performance-issues/troubleshooting-native-memory-leak-in-an-iis-7x-application-pool - Travis Acton
一个建议,尝试使用PerfView在应用程序池回收期间记录w3wp的跟踪(这是您修改web.config触发的)。 PerfView的内存使用分析在某些情况下非常有帮助。 https://www.microsoft.com/en-us/download/details.aspx?id=28567 - stames
4个回答

5
在您的分析中,我发现 .net 分析没有正确执行。您是在捕获内存转储的同一台机器上进行分析吗?
为了使 debugdiag 正确工作,您必须在分析机器上安装与应用程序相同版本的 .net framework。
另外,请不要像 this 一样进行本机内存泄漏转储,除非未解决非托管泄漏问题。根据您的分析,看起来这是托管泄漏。
当您更改 web.config 文件时,会导致应用程序域卸载和重新加载。
让我们一步一步来。
  1. 使用DebugDiag(捕获连续挂起转储)
    • 启动DebugDiag Collection并转到进程选项卡 debugdiag process tab
    • 开始您的压力测试
    • 检查内存使用情况,一旦达到1 GB,请捕获挂起转储
      • 右键单击w3wp.exe进程
      • 选择创建完整内存转储选项 capture full memory hang dump
    • 在2 GB和3.5 GB处捕获另一个转储文件
    • 您应该在C:\ ProgramFiles \ DebugDiag \ Logs \ Misc \文件夹中捕获了转储文件
    • 右键单击转储文件,选择分析.NET内存问题选项 Analyse .net memory issue
现在比较每个转储文件(1 GB、2 GB、3.5 GB)的分析,它应该会告诉您哪些.NET对象正在增加且未被垃圾回收。
在内存分析中,您应该看到类似下面的CLR信息****,.NET GC堆信息最耗费内存的.NET对象等内容。如果您的.NET符号已被debugdiag分析正确识别,则会出现这些内容。
CLR Information
 CLR version = 4.6.1648.0
 Microsoft.Diagnostics.Runtime version = 0.9.2.0
.NET GC Heap Information
Number of GC Heaps: 4 
Heap Size 0x4001ce8 (67,116,264) 
Heap Size 0x3d5cca0 (64,343,200) 
Heap Size 0x3f8b0d0 (66,629,840) 
Heap Size 0x3ccb0d0 (63,746,256) 
GC Heap Size 249.71 MBytes  
Total Commit Size  249 MB 
Total Reserved Size    17158 MB 

40 most memory consuming .NET object types

System.Char[]   193.01 MBytes    (12450 objects )
Free      45.21 MBytes    (4760 objects )
System.String      1.56 MBytes    (18072 objects ) 
==============trimmed out =======================

DebugDaig自动分析应该给出以下结果

  1. **错误或警告** - 注意debugdiag分析报告顶部显示的警告或错误。
  2. .NET GC堆信息 - 总提交大小 - 这将大致等于您的.NET内存使用情况。
  3. 最消耗内存的40种.NET对象类型 - 这可以用来与连续转储中的内存增加进行比较。这将告诉您哪些对象正在引起问题。有时,您根本不使用的某些对象会出现,并且可能来自某个第三方库。或者您将看到您自己创建的对象。
  4. 终结器队列中的顶级对象 - 这将为您提供任何线索,如果您的终结器可能被阻塞,则会出现对象。一些类似的问题在此处此处中讨论。
  5. 大对象堆上的对象 - 这会导致内存碎片,并且大对象堆包含超过85K大小的对象。
  6. 缓存、数据表、应用程序域、动态程序集等的大小。在一个进程中拥有大量应用程序域不是一个好主意。
请注意,有时候DebugDiag自动分析无法找出根本原因,需要使用Windbg进行手动分析。关于DebugDiag分析,请参考此视频
希望这有所帮助!

嗨,Rohith。感谢你的回答。我正在同一台机器上进行分析和捕获。请告诉我哪里不匹配 :) - Ashkan S
我也会尝试您的方法,但我猜警告应该与我的自动阈值转储(更新2)相同。 - Ashkan S
你在分析中获取了.NET GC堆信息吗?你的转储文件有多大? - Rohith
请确保您拥有v2工具 https://www.microsoft.com/en-us/download/confirmation.aspx?id=49924 - Matt Kocaj

1

由于您似乎可以复制您的问题,有时候最简单的方法是删除您认为可能是根本原因的东西,然后再次进行测试(除非您需要很多时间来看它是否会增长?)

在某个时候,错误将停止发生,您将知道哪段代码负责。

但是,根据您的代码库,删除代码并仍然拥有可测试的内容并不总是容易的(即没有使应用程序崩溃)。


1

解决内存泄漏问题需要两个步骤。

  1. 找到内存泄漏的位置。
  2. 修复内存泄漏。

通常第一步比较棘手。因此,我建议使用ANTS内存分析器,首先找出哪些实例确切地在增长

在IIS上对ASP.NET应用程序进行分析

在您的问题中,您展示了包括系统命名空间的类列表结果。为了清除噪音,您可以选择“仅显示具有源代码的类”选项。

enter image description here

然后按照以下步骤进行。

  1. 在执行任何操作之前,先进行基础快照。
  2. 执行您认为存在内存泄漏的操作。
  3. 再进行几个快照,直到获得一个相当稳定的快照。
  4. 将最后一个快照与基础快照进行比较,查看哪些实例正在增长。

0
您提到:“我在web.config中添加了一个空格,突然我的IIS进程在30分钟内开始增长到超过1 GB。”您将这个空格附加到了哪个web.config标签上?您的代码的哪一部分使用它?您的代码的这一部分是否无法处理某些异常而导致内存泄漏?使用PerfView(Dump GC heap)来分析dump文件。这可以精确地告诉我们,哪种类型的对象占用了这么多的内存。在较旧版本的.net中,可能是大对象堆(大数组)或打开和误处理的数据库连接和文件上的对象。

https://channel9.msdn.com/Series/PerfView-Tutorial/Tutorial-10-Investigating-NET-Heap-Memory-Leaks-Part1-Collecting-the-data

https://channel9.msdn.com/Series/PerfView-Tutorial/Tutorial-11-Investigating-NET-Heap-Memory-Leaks-Part2-Analyzing-the-data


嗨,阿米特。感谢你的回答。我在文件末尾添加了空格,在XML结构中不会有任何影响。如果我重新启动应用程序池,也会发生同样的事情。 - Ashkan S

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接