我不确定,因为我在分析内存转储方面没有太多经验,但我认为我们可能会遇到内存碎片问题。
在负载测试期间,我们看到内存使用量正在增长到应用程序重新启动的程度。它是 64 位机器上的 ASP.NET MVC 4 应用程序。我没有参与编写它。我只是被要求尝试分析内存转储。
因此,在上次负载测试期间,我们创建了 3 个内存转储(低于它们的大小和来自 eeheap -gc 的总 GC 堆大小输出):
- 1.70GB、292MB
- 2.03GB、337MB
- 2.55GB、347MB
因此,正如您所见,托管堆的增长速度不如转储文件。当我执行 dumpheap -stat 时,我看到大部分空间都被 Free 对象使用(下面是每个转储文件)
- 147MB
- 145MB
- 213MB
大于 0.5 MB 的碎片块: 地址大小后跟 000000bcc668e0a8 0.7MB 000000bcc6738650 System.Object[] 000000bcc6949f88 4.4MB 000000bcc6dab820 System.Collections.Specialized.NameObjectCollectionBase+NameObjectEntry 000000bd4626c4b8 0.7MB 000000bd463165f8 System.Byte[] 000000bd463fcc48 51.5MB 000000bd4977baf0 System.Threading.ThreadStart 000000be463600c8 0.7MB 000000be464108f0 免费 000000bec67e50e0 1.1MB 000000bec690b020 System.Collections.Generic.List`1[[OurType, ANotherOurType]] 000000bec690b0b8 3.2MB 000000bec6c3b170 System.Byte[] 000000bfc6605e00 1.0MB 000000bfc6710190 免费 000000bfc6743c58 32.8MB 000000bfc8806fe8 System.Threading.ExecutionContext 000000c046200580 1.0MB 000000c0462ff2a0 SomeOurType 000000c0463a1270 3.6MB 000000c046732ac0 Microsoft.Win32.SafeHandles.SafeCapiKeyHandle
据我了解,当 Free 对象仅占所有堆大小的内存总量的一小部分时,这不是问题。这里看起来是个问题。
应用程序正在使用两个外部库。一种用于创建 PDF-s,另一种用于创建条形码文件。条码库抛出 AccessViolationException(2200 次尝试大约 70 次)。它与此堆栈跟踪一起抛出
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
at System.Drawing.SafeNativeMethods.Gdip.IntGdipDeleteGraphics(HandleRef graphics)
at System.Drawing.Graphics.Dispose(Boolean disposing)
at System.Drawing.Graphics.Dispose()
at Lesnikowski.Barcode.BaseBarcode.Render()
at Lesnikowski.Barcode.BaseBarcode.Save(Stream stream, ImageType imageType)
我读过内存碎片通常是由固定内存引起的,但这是 !gchandles 输出
把手: 强力手柄:154 固定手柄:23 参考计数句柄:2 弱长手柄:1794 弱短柄:74 SizeRef 手柄:17 从属句柄:1
我不知道我还能检查什么。我们有内存碎片问题吗?你能给我指出一些方向吗?
编辑:我附上了负载测试期间收集的性能计数器。很奇怪,因为它显示了很多固定的对象,但 !gchandles 没有显示它们。
红线 - 用户负载 绿线 - 所有堆中的字节 蓝线 - 固定对象
Edit2:添加了大于 0.5 MB 的碎片块:来自 !dumpheap -stat 的输出