c++ - leer - ¿Análisis detallado del uso de la memoria del archivo de volcado de Windows?
volcado de memoria completa (3)
¿Cuántos basureros tienes ahora?
La forma correcta de rastrear la pérdida de memoria es hacer un buen uso de la regla de Fuga de memoria y manejo de DebugDiag.
Luego, cuando DebugDiag funciona en los nuevos volcados, puede decir más sobre el uso de la memoria.
Hemos recibido un archivo de volcado nativo (completo) de un cliente. Abrirlo en el depurador de Visual Studio (2005) muestra que tuvimos un bloqueo causado por una llamada de realloc que intentó asignar un bloque de ~ 10 MB. El archivo de volcado era inusualmente grande (1,5 GB, normalmente son más como 500 MB).
Por lo tanto, llegamos a la conclusión de que tenemos una "pérdida" de memoria o asignaciones fuera de control que agotaron completamente la memoria del proceso o, al menos, la fragmentaron de manera suficientemente significativa como para que el realloc falle. (Tenga en cuenta que esta asignación fue para una operación que asignó un búfer de registro y no nos sorprende que haya fallado aquí, porque 10MB de una sola vez sería una de las asignaciones más grandes que hacemos, aparte de algunos búferes muy grandes e inmutables: el problema probablemente no tenga nada que ver con esta asignación específica.)
Edit: Después del intercambio de comentarios con Lex Li a continuación, debo agregar: Esto no es reproducible para nosotros (en este momento). Es solo un volcado de clientes que muestra claramente el consumo de memoria fuera de control.
Pregunta principal:
Ahora tenemos un archivo de volcado, pero ¿cómo podemos localizar qué causó el uso excesivo de memoria?
Lo que hemos hecho hasta ahora:
Hemos utilizado la herramienta DebugDiag para analizar el archivo de volcado (el llamado analizador de presión de memoria), y esto es lo que obtuvimos:
Report for DumpFM...dmp
Virtual Memory Summary
----------------------
Size of largest free VM block 62,23 MBytes
Free memory fragmentation 81,30%
Free Memory 332,87 MBytes (16,25% of Total Memory)
Reserved Memory 0 Bytes (0,00% of Total Memory)
Committed Memory 1,67 GBytes (83,75% of Total Memory)
Total Memory 2,00 GBytes
Largest free block at 0x00000000`04bc4000
Loaded Module Summary
---------------------
Number of Modules 114 Modules
Total reserved memory 0 Bytes
Total committed memory 3,33 MBytes
Thread Summary
--------------
Number of Threads 56 Thread(s)
Total reserved memory 0 Bytes
Total committed memory 652,00 KBytes
Esto fue solo para obtener un poco de contexto. Cuál es más interesante que creo que es:
Heap Summary
------------
Number of heaps 26 Heaps
Total reserved memory 1,64 GBytes
Total committed memory 1,61 GBytes
Top 10 heaps by reserved memory
-------------------------------
0x01040000 1,55 GBytes
0x00150000 64,06 MBytes
0x010d0000 15,31 MBytes
...
Top 10 heaps by committed memory
--------------------------------
0x01040000 1,54 GBytes
0x00150000 55,17 MBytes
0x010d0000 6,25 MBytes
...
Ahora, mirando el montón 0x01040000
(1,5 GB) vemos:
Heap 5 - 0x01040000
-------------------
Heap Name msvcr80!_crtheap
Heap Description This heap is used by msvcr80
Reserved memory 1,55 GBytes
Committed memory 1,54 GBytes (99,46% of reserved)
Uncommitted memory 8,61 MBytes (0,54% of reserved)
Number of heap segments 39 segments
Number of uncommitted ranges 41 range(s)
Size of largest uncommitted range 8,33 MBytes
Calculated heap fragmentation 3,27%
Segment Information
-------------------
Base Address | Reserved Size | Committed Size | Uncommitted Size | Number of uncommitted ranges | Largest uncommitted block | Calculated heap fragmentation
0x01040640 64,00 KBytes 64,00 KBytes 0 Bytes 0 0 Bytes 0,00%
0x01350000 1.024,00 KBytes 1.024,00 KBytes 0 Bytes 0 0 Bytes 0,00%
0x02850000 2,00 MBytes 2,00 MBytes 0 Bytes 0 0 Bytes 0,00%
...
¿Qué es esta información del segmento de todos modos?
Mirando las asignaciones que se enumeran:
Top 5 allocations by size
-------------------------
Allocation Size - 336 1,18 GBytes
Allocation Size - 1120004 121,77 MBytes
...
Top 5 allocations by count
--------------------------
Allocation Size - 336 3760923 allocation(s)
Allocation Size - 32 1223794 allocation(s)
...
Podemos ver que aparentemente el montón MSVCR80 tiene 3.760.923 asignaciones en 336 bytes. Esto deja bastante claro que limpiamos nuestra memoria con muchas asignaciones pequeñas, pero ¿cómo podemos obtener más información sobre de dónde provino esta asignación ?
Si de alguna manera pudiéramos muestrear algunas de estas direcciones de asignación y luego verificamos en qué parte de la imagen de proceso se están utilizando estas direcciones, entonces, suponiendo que una gran parte de estas asignaciones sean responsables de nuestra "filtración", podríamos descubrir dónde estas asignaciones fuera de control vinieron de
Desafortunadamente, no tengo ni idea de cómo obtener más información del volcado en este momento.
¿Cómo podría inspeccionar este montón para ver algunas de las "336" direcciones de asignación?
¿Cómo puedo buscar estas direcciones en el volcado y luego averiguar qué variable de puntero (si existe) en la retención de volcado en estas direcciones?
¡Cualquier consejo relacionado con el uso de DebugDiag, WinDbg o cualquier otra herramienta realmente podría ayudar! Además, si no está de acuerdo con alguno de mis análisis anteriores, ¡avísenos! ¡Gracias!
En windbg, puede intentar usar !heap -l
que debería rastrear los montones (tarda un tiempo, puede haber una manera de restringir la búsqueda a un montón específico para acelerarlo) y encontrar todos los bloques ocupados que no están referenciados en ninguna parte . Desde allí, abra la ventana de memoria ( alt + 5 ) y eche un vistazo a algunas de las entradas que coinciden con el tamaño de su asignación que sospecha que es su fuga. Con algo de suerte, podría haber algunos patrones comunes que pueden ayudarlo a identificar cuáles son los datos o, mejor aún, algunas cadenas ASCII que puede colocar de inmediato.
Desafortunadamente, no conozco ninguna otra buena manera, excepto intentar reproducirla al activar los seguimientos de pila de modo de usuario con gflags y usar umdh para tomar instantáneas de memoria.
Tú podrías:
- investigue estos bloques de 336 bytes para ver si el contenido le dice algo sobre lo que les asignó. Para hacer eso, normalmente uso windbg. Primero ejecute el comando
!heap -stat -h 0x01040000
que le dará el tamaño del bloque, luego pase este tamaño a!heap -flt s
size que!heap -flt s
todos los bloques de ese tamaño. Luego puede mirar en el bloque con cualquier comando que muestre memoria (como dc). - no puede reproducir el problema, pero puede ver en otro volcado qué asigna bloques de ese tamaño. Primero active la función de retroceso de pila utilizando la utilidad
gflags -i your.exe +ust
(gflags -i your.exe +ust
). Luego ejecute su aplicación, obtenga un volcado y use el!heap -flt s
para enumerar los bloques. Luego, el comando!heap -p -a
blockaddress volcará la pila de funciones que asignaron el bloque.