Método de análisis y diagnóstico de Out Of Memory
En primer lugar, ¿qué es Out Of Memory? El desbordamiento de memoria se abrevia como OOM (¡usaré esta abreviatura a continuación!). Para decirlo sin rodeos, cuando el programa quiere usar memoria, el sistema operativo no tiene tanta memoria para asignar y luego ocurre un error de OOM.
Antes que nada, permítanme presentarme. La situación de este proyecto se basa en la llamada al servicio web Exchange sp hmc. Utiliza un programa de prueba de simulación winform para agregar información en un solo hilo y realizar bucles miles de veces. empresa y abre un nombre de dominio de correo electrónico y crea una cuenta. Cada cuenta abre el servicio de correo electrónico. Ahora se repite aproximadamente cuando la ocupación de memoria de wwp exe es bytes privados M bytes virtuales M. Escuché de mis hermanos que han hecho algo similar. pruebas Cuando el bucle llega a la herramienta súper genial debugdiag. (Esta herramienta se presentará más adelante porque es realmente doloroso publicar N muchas imágenes...) Use debugdiag para capturar el volcado de pérdida de memoria (M) y encontró el siguiente problema: mscorwks filtró información sobre la memoria M
Ahora ve a windbg. ¡Veamos primero los comandos! eeheap tiene dos parámetros
gt; ayuda eeheap
! EEHeap [ gc] [ loader]
¡Primero, eche un vistazo a los parámetros de gc! eeheap gc Este comando indica el tamaño del montón administrado ocupado por nuestro programa
> gt; eeheap gc
Número de montones de GC
La generación comienza en x ff f
La generación comienza en x f df c
La generación comienza en x c
contexto de asignación de segmento efímero (x bcbf x bd c)
tamaño asignado de inicio del segmento
ead a c c a d x edc ( )
e a d a f b x f b ( )
c c bd c x fc c( )
El montón de objetos grandes comienza en x c
el segmento comienza con el tamaño asignado
c c cfbbd x abd ( )
Tamaño total xa d ( )
Tamaño del montón de GC xa d ( )
El tamaño del volcado es M Tamaño del montón administrado ¡Hay una gran diferencia para M! ¿Dónde está el resto del recuerdo? ¡Ahora veamos un nuevo comando! Después de ejecutar la dirección, habrá una gran cantidad de resultados. Lo que nos importa es el siguiente resumen.
RESUMEN de uso
TotSize (KB) Pct (Tots) Pct (Ocupado) Uso
p>
b ( ) RegionUsageIsVAD
c b ( ) RegionUsageFree
d ( ) RegionUsageImage
fc ( ) RegionUsageStack
( ) RegionUsageTeb
( ) RegionUsageHeap
( ) RegionUsagePageHeap
( ) RegionUsagePeb
( ) RegionUsageProcessParametrs
( ) RegionUsageEnvironmentBlock
Tot fff (KB) Ocupado b c (KB)
RESUMEN de tipo
TotSize (KB) Pct (Tots) Uso
c b ( ) lt freegt; ( ) MEM_IMAGE
a ( ) MEM_MAPPED
a d ( ) MEM_PRIVATE
Estado RESUMEN
TotSize (KB) Pct (Tots) Uso
ee ( ) MEM_MIT
c b ( ) MEM_FREE
ca ( ) MEM_RESERVE
La información anterior es más interesante que RegionUsageImage representa archivos DLL. La memoria ocupada es M. RegionUsageheap representa montones de NT. La memoria ocupada es M. La suma de MEM_MIT y MEM_RESERVE es memoria virtual. El total de ellos es M. ¿Qué nos hemos perdido? ! Hay otro parámetro de eeheap, que es el cargador. Después de ejecutarlo, habrá N resultados largos. ¡Echemos un vistazo a una parte
! eeheap –loader
Dominio fbd
LowFrequencyHeap ba ( ) d ( ) ee ( ) b ( ) ea ( ) f ( f ) ( ) Muy amarillo y violento... edc ( ) ee ( ) Tamaño x ce ( ) bytes
X ( ) bytes desperdiciados
HighFrequencyHeap ba ( ) e ( f ) aa ( ) c ( f ) ( ) ( ) d ( ) Eba muy amarillo y violento ( ) ee ( ) Tamaño x a ( ) bytes
Desperdiciado x ( ) bytes
StubHeap baa ( ) Tamaño x ( ) bytes
Montón de código auxiliar de llamadas virtuales
Tamaño de IndcellHeap x ( ) bytes
Tamaño de LookupHeap x ( ) bytes
Tamaño de ResolveHeap x ( ) bytes
Tamaño de DispatchHeap x ( ) bytes
p>
CacheEntryHeap bc ( ) Tamaño x ( ) bytes
Tamaño total x c ( ) bytes
Una *** memoria M ocupada Continúe leyendo el siguiente contenido. y descubrí ¡Tengo un módulo! ! !
Montones de procesadores de módulo
Tamaño de módulo aa x ( ) bytes
Tamaño de módulo e x ( ) bytes
Tamaño de módulo a x ( ) bytes
Tamaño del módulo x ( ) bytes
============= Muy pornográfico y violento =========== ===========
Tamaño del módulo ee x ( ) bytes
Tamaño del módulo ee x ( ) bytes
Tamaño del módulo ee c x ( ) bytes
Tamaño del módulo ee c x ( ) bytes
Tamaño total x ( ) bytes
Tamaño total de LoaderHeap x a f ( ) bytes
========================================= ==
¡El problema básicamente ha surgido! ¡Hay casi 10,000 módulos en la memoria! ¡Simplemente tírelo y vea si hay otro comando aquí! dumpmodule
¡Simplemente descargue uno y vea información similar a la siguiente
gt; dumpmodule ee
Nombre qrt x cw Versión= Cultura=neutral PublicKeyToken=null
Atributos PEFile
Ensamblaje cf e
LoaderHeap
LoaderHeap
p>
p>
TypeDefToMethodTableMap edcc
TypeRefToMethodTableMap edcc c
MethodDefToDescMap edcc c
FieldDefToDescMap edcc
MemberRefToDescMap edcc c
FileReferencesMap edcc
AssemblyReferencesMap edcc
Dirección inicial de metadatos ed (bytes)
Es posible que no veas nada aquí, así que agreguemos un parámetro mt para echarle un vistazo
gt;! dumpmodule mt ee
Nombre qrt x cw Versión= Cultura=neutral PublicKeyToken=null
Atributos PEFile
Ensamblaje cf e
LoaderHeap
TypeDefToMethodTableMap e
dcc
TypeRefToMethodTableMap edcc c
MethodDefToDescMap edcc c
FieldDefToDescMap edcc
MemberRefToDescMap edcc c
FileReferencesMap edcc
AssemblyReferencesMap edcc
Dirección inicial de metadatos ed (bytes)
Tipos definidos en este módulo
MT TypeDef Name
ee c x Serialización Xml de Microsoft GeneratedAssembly XmlSerializationReaderCreateUserResponseData
ee c x Serialización Xml de Microsoft GeneratedAssembly Nombre
e eac x Serialización Xml del sistema XmlSerializationReader
e b x Serialización Xml del sistema >
e be x System Xml XmlReader
fd cc x Tabla hash de colecciones del sistema
f a x e Objeto del sistema
e c x System Xml XmlQualifiedName
c x System Boolean
e a b x System Xml XmlNameTable
Aparece la serialización de System Xml. Pasemos a la pila de llamadas analizada por debugdiag
Muestra de pila de llamadas
Dirección x c
Tiempo de asignación desde que comenzó el seguimiento
Tamaño de asignación en bytes
Función Fuente Destino
mscorjit! norls_allocator nraAllocNewPage
mscorjit! norls_allocator nraAlloc mscorjit! norls_allocador
nraAllocNewPage
mscorjit! jitNativeCode mscorjit! norls_allocator nraAlloc
mscorjit! CILJit pileMétodo d mscorjit! jitNativeCode
x E C E
mscorjit! Compilador impExpandInline aa
mscorjit! Compilador fgMorphTree
mscorjit! Compilador fgMorphStmts mscorjit! Compilador fgMorphTree
mscorjit! Compilador fgMorphBlocks mscorjit! Compilador fgMorphStmts
mscorjit! Compilador fgMorph mscorjit! Compilador fgMorphBlocks
mscorjit! Compilador pCompile f mscorjit! Compilador fgMorph
mscorjit! Compilador pCompile d mscorjit! Compilador pCompile
mscorjit! jitNativeCode b mscorjit! Compilador pCompile
mscorjit! CILJit pileMétodo d mscorjit! jitNativeCode
x EED FF
Sistema de serialización Xml TempAssembly InvokeReader(Sistema de serialización Xml XmlMapping Sistema de Xml XmlReader Sistema de serialización Xml (Sistema de serialización Xml XmlMapping Sistema de Xml XmlReader Sistema de serialización Xml XmlDeserializationEvents Cadena del sistema)
Serialización Xml del sistema XmlReader Serialización Xml del sistema XmlDeserializationEvents Cadena del sistema
ing)
Sistema Xml Serialización XmlSerializer Deserialize (System Xml XmlReader System String) System Xml Serialization XmlSerializer Deserialize (System System IO Stream) System Xml Serialization XmlSerializer Deserialize (System Xml XmlReader System String)
Microsoft Provisioning Sdk Deserialize(System IO Stream)
Microsoft Provisioning WebServices ServiceBase Enviar[[System __Canon mscorlib] [System __Canon mscorlib]](System __Canon System String System String Boolean) Microsoft Provisioning Sdk Xml Serialización ProvisioningObjectFactory Convertir [[Sistema __Canon mscorlib] [Sistema __Canon mscorlib]] (Sistema __Canon)
Microsoft Provisioning WebServices HostedActiveDirectory Service CreateOrganization (Microsoft Provisioning WebServices HostedActiveDirectory CreateOrganizationRequest booleano)
x E BE B p>
x A E E
Protocolos de servicios web del sistema Invocación LogicalMethodInfo(Objeto del sistema Objeto del sistema[])
Protocolos de servicios web del sistema Invocación WebServiceHandler() Protocolos de servicios web del sistema Invocación LogicalMethodInfo( Objeto del sistema Objeto del sistema
t[])
x F FC
Subprocesos del sistema _TimerCallback TimerCallback_Context (objeto del sistema)
Ejecución de subprocesos del sistema ExecutionContext (objeto del sistema ContextCallback de subprocesos del sistema ExecutionContext)
motor web! HashtableIUnknown AddCallback un
motor web! HttpCompletion ProcessRequestInManagedCode un
motor web! HttpCompletion ProcessRequestInManagedCode un
motor web! HttpCompletion ProcessCompletion y motor web! HttpCompletion ProcessRequestInManagedCode
webengine! CorThreadPoolWorkitemCallback
x F
x F BC
kernel ! BaseThreadStart
Viendo esto, es básicamente lo mismo, creo que es un problema de código interno ¿Qué dices? Comencemos desde el principio. Hay un error de diseño en Serialización XML del sistema. Usamos reflector para ver el código de construcción de )
{
Bloqueo (caché)
.{
este tempAssembly = cache[tipo de espacio de nombre predeterminado]
if (este tempAssembly == null)
{
XmlSerializerImplementation implementación
Ensamblaje ensamblaje = TempAssembly LoadGeneratedAssembly (escriba defaultNamespace fuera de implementación)
if (assembly == null)
{
esta asignación = nuevo XmlReflectionImporter(defaultNamespace) ImportTypeMapping(tipo nulo defaultNamespace)
tipo predeterminado
ltNamespace)
}
else
{
esta asignación = XmlReflectionImporter GetTopLevelMapping(tipo defaultNamespace)
esta tempAssembly = new TempAssembly(new >
}
Para acelerar la velocidad de ejecución, xmlserializer tiene un caché. Quizás tengamos N tipos más en el código, por lo que cada tipo tiene un ensamblado aquí. y el ensamblado se coloca en el caché. De esta manera, no hay problema, pero si hay miles o decenas de miles de tipos, entonces habrá decenas de miles de ensamblados temporales. Estos ensamblados son muy pequeños, tal vez solo un byte, tal vez. un byte, pero tenga en cuenta que cuando se asigna memoria, se asigna en bloques. Si cada bloque tiene al menos un tamaño k, incluso si solo asignamos un byte de memoria, aún necesitamos solicitar una página de k. Si tenemos muchísimos bloques pequeños, después de reducir N veces, encontrará que la memoria está en todas partes. Estos agujeros se suman a un agujero grande, pero otros no pueden usarlo porque hay k. la memoria debe estar en bloques continuos
Entonces, cuando descubrimos que w wp exe tenía solo 100 megabits, informó OOM. Esta es la razón lishixinzhi /Article/program/net/201311/12615
.