.NET WCF w3wp本机内存泄漏和装载器堆中0个大小的18k动态程序集

Pra*_*vin 37 .net c# memory memory-leaks windbg

我们的WCF服务显示了大量内存使用的实例,因此我们采用了完整的内存转储来识别问题.

Operating System   Windows Server 2008 R2Service Pack 1 
Number Of Processors   4 
Process Image   c:\Windows\System32\inetsrv\w3wp.exe 
System Up-Time   40 day(s) 09:23:09 
Process Up-Time   14 day(s) 11:49:01 
.NET 4.0
Processor Type   X64 
Process Bitness   64-Bit
Run Code Online (Sandbox Code Playgroud)

DebugDiag报告中问题的直升机视图.

  1. 进程是垃圾收集,所以根据警告,我不应该信任!heap命令的所有输出.

  2. Gc堆:1.37 GBytes

  3. .NET Cache大小为750Mb,

    虚拟内存详细信息:虚拟分配:17.45 Gb加载模块:208.68 Mb线程:25 Mb本机堆:3.06 Gb(我担心这个.)

从上方3.02 Gb存在于Heap 0x003f0000单独.我们有很好的流量,这样1.3 gbGc堆大小对我来说是正常的.我们还有32 gbram和64bit地址空间的机器,因此Cache大小750 mb是可以接受的.根据Native堆的大小,我觉得这是本机内存泄漏.

DebugDiag警告: 转储文件中加载了18149个动态程序集.

帮助链接:
.NET内存泄漏:XmlSerial化您的内存泄漏
分析 - 我们使用XmlSerialisers但它们被缓存,这样它们只创建一次.

.NET内存泄漏:XslCompiledTransform和泄漏的动态程序集
我们似乎在此博客文章中描述了同样的问题.所有这些18149动态组件都是0尺寸.所以我不能抛弃它们来获取细节.此外,我们不在此应用程序的任何位置使用Xsl转换.所以这些程序集不是由于Xsl转换.

更多统计数据:
相关对象数:

System.Reflection.Emit.InternalModuleBuilder -----   1.11 MBytes    (18149 objects )
System.Reflection.Emit.InternalAssemblyBuilder ----- 992.52 KBytes    (18149 objects ) 
System.Reflection.Emit.__FixupData[]  ----------   595.41 KBytes    (752 objects )
System.Reflection.Emit.GenericFieldInfo  ----------  580.03 KBytes    (18561 objects )
System.Reflection.RuntimeMethodInfo  ----------   1.2 MBytes    (11276 objects )
System.RuntimeType --------------------     1.13 MBytes    (21228 objects )
Run Code Online (Sandbox Code Playgroud)

Finalizer队列中的热门对象

System.Reflection.Emit.DynamicResolver - 379 System.Reflection.Emit.DynamicResolver+DestroyScout - 271

应用领域统计
Domain - Default - 13 assemblies - size : 89,677,824 (90 Mb ~) Domain - ROOT/tv/Engine1 - 18236 Assemblies- Size :152,834,048 (150 Mb ~)

我猜这些泄漏的动态组件占据了150 Mb的空间.不确定3 Gb本机内存是否是由于这些程序集?

更多关注这个组件:

!dumpdomain 给我大型的Unknown动态组件如下:

Assembly:           000000000fa9d0d0 (Dynamic) []
ClassLoader:        0000000002be1d40
SecurityDescriptor: 000000000fc08a00
  Module Name
000007fe96d38e68            Dynamic Module

and  !EEHeap -loader gives same number of 0 sized modules : 
Module 000007fea0b7b758: Size: 0x0 (0) bytes.
Module 000007fea0b7c1e8: Size: 0x0 (0) bytes.
Module 000007fea0b7cc78: Size: 0x0 (0) bytes.
Run Code Online (Sandbox Code Playgroud)

检查阻塞的GC终结器线程不是这种情况,从下面的堆栈跟踪.它正在等待Finalization事件发生.

0:000> ~20 k
Child-SP          RetAddr           Call Site
00000000`0eedf3b8 000007fe`fd6f1430 ntdll!ZwWaitForMultipleObjects+0xa
00000000`0eedf3c0 00000000`77501723 KERNELBASE!WaitForMultipleObjectsEx+0xe8
00000000`0eedf4c0 000007fe`f60939d4 kernel32!WaitForMultipleObjectsExImplementation+0xb3
00000000`0eedf550 000007fe`f6094799 clr!SVR::WaitForFinalizerEvent+0xcc
00000000`0eedf590 000007fe`f5f0458c clr!SVR::GCHeap::FinalizerThreadWorker+0x4a
00000000`0eedf5d0 000007fe`f5f0451a clr!Frame::Pop+0x50
Run Code Online (Sandbox Code Playgroud)

转储与泄漏的动态程序集具有相同数量的对象System.Reflection.Emit.InternalModuleBuilderSystem.Reflection.Emit.InternalAssemblyBuilder对象.

我注意到System.Reflection.Emit.DynamicResolver在Top finalizer队列中并转储所有这些并将它们与动态程序集地址相关联,如下所示.

转储5个DynamicResolver对象并进行跟踪DynamicResolver -> m_method -> m_module (00000001801728a0)

00000001801728a0这是InternalModuleBuilder列表中一个模块的地址.他们中的大多数都指向同一模块.

0:000> !dumpheap -type System.Reflection.Emit.DynamicResolver
         Address               MT     Size
000000018017d5a8 000007fef4c7c8b0       72     
000000018018d5b0 000007fef4c7c8b0       72     
00000001801931b0 000007fef4c7c8b0       72     
------- and on


0:000> !do 000000018017d5a8
Name:        System.Reflection.Emit.DynamicResolver
MethodTable: 000007fef4c7c8b0
EEClass:     000007fef4754300
Size:        72(0x48) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef4c44458  4002aaa        8      System.Object[]  0 instance 0000000000000000 m_exceptions
000007fef4c9a690  4002aab       10        System.Byte[]  0 instance 0000000000000000 m_exceptionHeader
000007fef4ca20c0  4002aac       18 ...mit.DynamicMethod  0 instance 0000000180172690 m_method
000007fef4c9a690  4002aad       20        System.Byte[]  0 instance 000000018017d5f0 m_code
000007fef4c9a690  4002aae       28        System.Byte[]  0 instance 000000018017d650 m_localSignature
000007fef4c992b8  4002aaf       38         System.Int32  1 instance                3 m_stackSize
000007fef4c7c788  4002ab0       30 ...Emit.DynamicScope  0 instance 0000000180172b80 m_scope

0:000> !do 0000000180172690 
Name:        System.Reflection.Emit.DynamicMethod
MethodTable: 000007fef4ca20c0
EEClass:     000007fef475e298
Size:        112(0x70) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef4c44458  4002ac6        8      System.Object[]  0 instance 0000000180172700 m_parameterTypes
000007fef4cafa88  4002ac7       10 ...RuntimeMethodInfo  0 instance 000000018017d678 m_methodHandle
000007fef4c987f8  4002ac8       18   System.RuntimeType  0 instance 00000004800e7900 m_returnType
000007fef4c7c578  4002ac9       20 ...ynamicILGenerator  0 instance 0000000180172a30 m_ilGenerator
000007fef4c4eb18  4002aca       28 ...mit.DynamicILInfo  0 instance 0000000000000000 m_DynamicILInfo
000007fef4c97de0  4002acb       60       System.Boolean  1 instance                1 m_fInitLocals
000007fef4c9f1d8  4002acc       30 ...ion.RuntimeModule  0 instance 00000001801728a0 m_module
000007fef4c97de0  4002acd       61       System.Boolean  1 instance                0 m_skipVisibility
000007fef4c987f8  4002ace       38   System.RuntimeType  0 instance 0000000000000000 m_typeOwner
000007fef4c7c330  4002acf       40 ...d+RTDynamicMethod  0 instance 00000001801729d8 m_dynMethod
000007fef4c7c8b0  4002ad0       48 ...t.DynamicResolver  0 instance 000000018017d5a8 m_resolver
000007fef4c97de0  4002ad1       62       System.Boolean  1 instance                0 m_profileAPICheck
000007fef4c99d18  4002ad2       50 ...n.RuntimeAssembly  0 instance 0000000000000000 m_creatorAssembly
000007fef4c97de0  4002ad3       63       System.Boolean  1 instance                1 m_restrictedSkipVisibility
000007fef4c88d70  4002ad4       58 ...g.CompressedStack  0 instance 00000001801729b0 m_creationContext
000007fef4c88020  4002ad5     16b8 ...rnalModuleBuilder  0   shared           static s_anonymouslyHostedDynamicMethodsModule
                                 >> Domain:Value  0000000002b66ba0:NotInit  0000000002c24a90:00000001801728a0 <<
000007fef4c96ae8  4002ad6     16c0        System.Object  0   shared           static s_anonymouslyHostedDynamicMethodsModuleLock
                                 >> Domain:Value  0000000002b66ba0:NotInit  0000000002c24a90:0000000180172798 <<


Opened log file 'C:\debug\new_dynamic_asm.log'
0:000> !dumpheap -type System.Reflection.Emit.InternalModuleBuilder
         Address               MT     Size
00000001800fe918 000007fef4c88020       64     
00000001801728a0 000007fef4c88020       64     
000000018017fa88 000007fef4c88020       64     
00000001801bee20 000007fef4c88020       64  
------- and on
Run Code Online (Sandbox Code Playgroud)

我对WinDbg不太方便,有人能给我一些线索.

  1. 如何将上述动态模块联系起来以触及有缺陷的代码.我相信这是由于Linq或Lambda的表达.
  2. 根据报告,动态程序集的大小为150 Mb,3 Gb泄漏会有任何不同,或者动态模块可能会链接到某些本机内存.

!heap -l给了我188722个潜在的无法访问的块被检测到.

使用WinDbg PyKd插件的本机堆统计信息给了我低于本机堆的统计信息.

注意值在18,000左右滚动

Statistics:

                                         Type name       Count  Size

                                    clr!RecordPool      817335  Unknown

                                       clr!RegMeta      272445  Unknown

                                 clr!CBlobPoolHash       36326  Unknown

                                  clr!MDInternalRW       36326  Unknown

                                   clr!StgBlobPool       36326  Unknown

                                       clr!CCeeGen       36298  Unknown

                                    clr!PEAssembly       18267  Unknown

                    clr!AssemblySecurityDescriptor       18249  Unknown

                                clr!DomainAssembly       18249  Unknown

                      clr!SharedSecurityDescriptor       18236  Unknown

                               clr!CStringPoolHash       18163  Unknown

                                     clr!CMiniMdRW       18163  Unknown

                                   clr!StgGuidPool       18163  Unknown

                                 clr!StgStringPool       18163  Unknown

                                 clr!CCustAttrHash       18163  Unknown

                                 clr!CGuidPoolHash       18163  Unknown

                                  clr!PESectionMan       18149  Unknown

                              clr!CeeSectionString       18149  Unknown

                                     clr!PESection       18149  Unknown

                           nativerd!CONFIG_ELEMENT        4932  Unknown

                          nativerd!ATTRIBUTE_VALUE        3912  Unknown

                         nativerd!SCHEMA_ATTRIBUTE        1473  Unknown

                                 clr!CAssemblyName        1116  Unknown

                     nativerd!COLLECTION_KEY_ENTRY         919  Unknown

                           nativerd!SCHEMA_ELEMENT         766  Unknown

                      clr!AssemblyMDInternalImport         720  Unknown

                           nativerd!CONFIG_SECTION         652  Unknown

                        nativerd!CONFIG_COLLECTION         570  Unknown

                 clr!ListNode<CHashNode * __ptr64>         444  Unknown
Run Code Online (Sandbox Code Playgroud)

Dom*_*icz 0

要诊断什么正在使用大量内存,您需要使用

!dumpheap -stat

这将通过对实例数求和来总结对象的使用情况。囤积内存的区域之一是大对象堆(任何超过 85k 的对象)。除非绝对必要,否则不会对该区域进行 GC。

要具体查看 LOH,您可以使用:

!dumpheap -stat -min 85000

对于上面您关心的项目,您需要找出它们属于哪一代。这可以通过查找项目的地址然后查看输出来完成,!DumpObject如下所示:

> 0:000> !do 0x0000000011b47450 
Name: System.Byte[]
MethodTable: 000007fef7d2e798
EEClass: 000007fef7932670
Size: 131096(0x20018) bytes
GC Generation: 3  <--- ****** Gen 3 == LOH
Array: Rank 1, Number of elements 131072, Type Byte
Element Type: System.Byte
Fields:
None
Run Code Online (Sandbox Code Playgroud)

如果您的示例中是 Gen 3,您将需要了解它是什么数据结构。85k+连续通常是byte[]strings。