c# .net memory memory-leaks windbg

c# - Fuga de memoria nativa WCF w3wp.NET y conjuntos dinámicos de 18k de 0 tamaños en el montón de cargadores



memory memory-leaks (5)

Nuestro servicio WCF mostró una Instancia de gran uso de memoria, por lo que tomamos un volcado de memoria completo para identificar el problema.

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

Vista en helicóptero del problema del informe DebugDiag.

  1. El proceso consistía en la recolección de basura, por lo que según la advertencia, no debería confiar en todos los resultados de los comandos! Heap.

  2. Gc montón: 1.37 GBytes

  3. El tamaño de la caché .NET es de 750Mb,

    Detalles de la memoria virtual: Asignaciones virtuales: módulos cargados de 17,45 Gb: 208,68 hilos de Mb: 25 Mb Montones de nativos: 3,06 Gb (me preocupa esto).

Desde arriba 3.02 Gb está presente en Heap 0x003f0000 solo. Tenemos buena cantidad de tráfico, de esa manera el tamaño de pila de 1.3 gb Gc me parece normal. También tenemos una máquina con 32 gb RAM y espacio de direcciones de 64 bits, por lo que el tamaño de caché de 750 mb es aceptable. Según el tamaño del montón nativo, creo que esta es la pérdida de memoria nativa.

Advertencia de DebugDiag: hay 18149 ensamblados dinámicos cargados en el archivo de volcado.

Enlaces de ayuda:
.NET Memory Leak: XmlSerializando su camino a un fuga de memoria
Análisis: usamos XmlSerialisers, pero están en caché, de esta forma se crean solo una vez.

.NET Memory Leak: XslCompiledTransform y ensamblajes dinámicos filtrados
Parece que tenemos el mismo tipo de problema descrito en esta publicación de blog. Todos estos conjuntos dinámicos 18149 son de 0 tamaños. Entonces no puedo volcarlos para obtener detalles. Además, no usamos la transformación Xsl en ninguna parte de esta aplicación. Entonces estos ensambles no se deben a transformaciones Xsl.

Algunas estadísticas más:
Recuento de objetos relacionados:

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 )

Top Objects en la cola del Finalizador

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

Estadísticas de dominio de aplicación
Domain - Default - 13 assemblies - size : 89,677,824 (90 Mb ~) Domain - ROOT/tv/Engine1 - 18236 Assemblies- Size :152,834,048 (150 Mb ~)

Supongo que estos ensambles dinámicos filtrados representan 150 Mb de espacio. ¿No está seguro de si 3 Gb de memoria nativa se debe a estos ensamblajes?

Más explorando con estas asambleas:

!dumpdomain me da grandes conjuntos dinámicos desconocidos como a continuación:

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.

Comprobado el final del GC Finalizer bloqueado, no es el caso, desde el seguimiento de la pila inferior. Está esperando que ocurra el evento de Finalización.

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

Dump tiene el mismo número de objetos System.Reflection.Emit.InternalModuleBuilder y System.Reflection.Emit.InternalAssemblyBuilder que los conjuntos dinámicos filtrados.

Noté System.Reflection.Emit.DynamicResolver en la cola del System.Reflection.Emit.DynamicResolver finalizador y los vacié a todos y los correlacioné con la dirección del ensamblaje dinámico de la siguiente manera.

Volcado alrededor de 5 objetos DynamicResolver y seguido DynamicResolver -> m_method -> m_module (00000001801728a0)

00000001801728a0 esta es la dirección de un módulo de la lista de la lista InternalModuleBuilder. La mayoría de ellos apuntaba al mismo módulo.

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

No soy tan útil con WinDbg, ¿alguien puede darme algunas pistas?

  1. Cómo relacionar los módulos dinámicos anteriores para llegar al código con errores. Creo que esto se debe a la expresión de Linq o Lambda.
  2. Según el informe, el tamaño de los ensambles dinámicos es de 150 Mb, la fuga de 3 Gb será diferente o los módulos dinámicos podrían estar enlazando con alguna memoria nativa.

! heap -l me dio 188722 bloqueos potenciales inalcanzables fueron detectados.

Las estadísticas nativas del montón usando el plugin PyKd de WinDbg me dieron a continuación las estadísticas del montón nativo.

Observe que los valores rondan los 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



Hemos visto problemas con pisando y NO usando colecciones seguras para subprocesos en el código. Dado que a la mayoría de la gente le gusta leer datos en colecciones, esto parece ser un problema "repetido" con pisadas y cosas por el estilo.

Vea aquí una lista de colecciones seguras para hilos: Thread Safe Collections

Una cosa mas que agregar. Usamos Profiler RedGate / ANTS. También verifique su conexión mgmt y la limpieza del código del Servicio WCF.


Para diagnosticar qué está usando una gran cantidad de memoria, desea usar

!dumpheap -stat .

Esto resumirá el uso del objeto al sumar el número de instancias. Un área que acumula memoria es el gran montón de objetos (cualquier cosa superior a 85k). Esta región no será aprobada por GC hasta que sea absolutamente necesario.

Para ver específicamente LOH, puede usar:

!dumpheap -stat -min 85000

Para los elementos que le interesan arriba, necesita saber en qué generación se encuentran. Esto se puede hacer con la búsqueda de la dirección del artículo y luego viendo la salida de !DumpObject manera:

> 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

Si es Gen 3 en su ejemplo, tendrá que ver qué estructura de datos es. 85k + continuo es generalmente byte[] o string s.


Solo como una sugerencia salvaje, puedo decirle que los servicios de WCF almacenados (por defecto) consumen mucha memoria extra. Si cambió al flujo continuo, podría obtener un gran ahorro de memoria.

Consulte este artículo https://msdn.microsoft.com/en-us/library/ms731913(v=vs.110).aspx .

En un caso, mi servicio WCF redujo el uso de memoria en 512meg al cambiar a modo de búfer.


WCF genera automáticamente clases de serialización en memoria para algunos protocolos de comunicación, principalmente para comunicación XML, y parece crear una clase diferente para cada posible variación en la estructura del mensaje; esto explica fácilmente el número de conjuntos. Este comportamiento es aparentemente normal para los protocolos WCF basados ​​en XML. Si tiene control sobre el protocolo, cambiar a un protocolo de comunicación que no sea XML puede resolver este problema.

El consumo de memoria de 3 GB es razonable para esto: el ensamblaje dinámico existirá tanto en MSIL (lenguaje ensamblador .NET) como en versiones nativas en la memoria. Los 150MB son probablemente para la versión MSIL que fue inicialmente generada por WCF, y no incluye el código nativo que genera el compilador .NET JIT tan pronto como la versión MSIL se "carga" como un módulo y se puede llamar.

El espacio virtual de 17.45 GB no es una memoria real, sino que es la distancia entre las ubicaciones de memoria más baja y más alta donde esos módulos se cargan; por ejemplo, si el módulo principal se carga en el desplazamiento 0, y el primer ensamblaje dinámico se carga en 00000000: 0b000000, la memoria virtual total listada será de aproximadamente 185MB, incluso si el módulo principal solo toma 2MB y el ensamblaje dinámico toma otros 2MB. Este es un ejemplo exagerado, ya que generalmente están empaquetados bastante bien, pero 1MB es típico entre direcciones, entonces 18000 * 1MB = 18000MB, que dividido por 1024 da exactamente 17GB de espacio de direcciones (agregue otro medio GB para el resto de su sistema y tienes el espacio completo de direcciones virtuales).

También he visto un tipo más de fuga de memoria de rápido crecimiento con WCF: si cualquier parte de un mensaje es retenida por un componente persistente de la aplicación, el objeto COM XML subyacente no será recolectado como basura, lo que resulta en cantidades bastante grandes de memoria goteando .NET XML DOM utiliza el subsistema XML COM de Windows, que es un código nativo, y lo asigna en un montón nativo. Esto podría explicar la diferencia entre montones de memoria administrados y nativos. Eche un vistazo a la memoria real en el volcado (busque una herramienta que pueda filtrar el texto imprimible), y verifique cuánto está formateado en XML.

He visto estas dos filtraciones y consumir rápidamente toda la memoria en servidores a gran escala, por lo que espero que mi experiencia brinde una respuesta para usted o, al menos, le dé algunos consejos adicionales para rastrear su problema.