usar lost leaks definitely como c valgrind

lost - ¿Cómo uso valgrind para encontrar fugas de memoria?



valgrind ubuntu (3)

¿Cómo uso valgrind para encontrar las fugas de memoria en un programa?

¿Alguien que me ayude y describa los pasos para llevar a cabo el procedimiento?

Estoy usando Ubuntu 10.04 y tengo un programa de ac , por favor, ayúdame.


Cómo ejecutar Valgrind

Me gustaría construir una explicación más detallada sobre cómo usar Valgrind de manera efectiva y cómo resolver las fugas de memoria. No para insultar al OP, pero para aquellos que llegan a esta pregunta y aún son nuevos en Linux, es posible que tenga que instalar Valgrind en su sistema.

sudo apt install valgrind # Ubuntu, Debian, etc. sudo yum install valgrind # RHEL, CentOS, Fedora, etc.

Valgrind es fácilmente utilizable para el código C / C ++, pero incluso puede usarse para otros idiomas cuando se configura correctamente (vea this para Python).

Para ejecutar valgrind , pase el archivo ejecutable como un argumento (junto con cualquier parámetro al programa).

valgrind --leak-check=full / --show-leak-kinds=all / --track-origins=yes / --verbose / --log-file=valgrind-out.txt / ./executable exampleParam1

Esto producirá un informe al final de la ejecución de su programa que (con suerte) se verá así:

HEAP SUMMARY: in use at exit: 0 bytes in 0 blocks total heap usage: 636 allocs, 636 frees, 25,393 bytes allocated All heap blocks were freed -- no leaks are possible ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Tengo una fuga, pero ¿ DÓNDE ?

Entonces, tienes una pérdida de memoria, y Valgrind no está diciendo nada significativo. Quizás, algo como esto:

5 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x4C29BE3: malloc (vg_replace_malloc.c:299) by 0x40053E: main (in /home/Peri461/Documents/executable)

Echemos un vistazo al código C que escribí también:

#include <stdlib.h> int main() { char* string = malloc(5 * sizeof(char)); //LEAK: not freed! return 0; }

Bueno, hubo 5 bytes perdidos. ¿Como paso? El informe de errores solo dice main y malloc . En un programa más grande, eso sería seriamente problemático de cazar. Esto se debe a cómo se compiló el ejecutable . Realmente podemos obtener detalles línea por línea sobre lo que salió mal. Recompila tu programa con una marca de depuración (estoy usando gcc aquí):

gcc -o executable -std=c11 -Wall main.c # suppose it was this at first gcc -o executable -std=c11 -Wall -ggdb3 main.c # add -ggdb3 to it

Ahora, con esta compilación de depuración, ¡ Valgrind apunta a la línea exacta de código que asigna la memoria que se filtró! (La redacción es importante: puede que no sea exactamente donde está la fuga, sino qué se filtró. La traza lo ayuda a encontrar dónde ).

5 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x4C29BE3: malloc (vg_replace_malloc.c:299) by 0x40053E: main (main.c:4)

Técnicas para depurar fugas de memoria y errores

  • ¡Utilice www.cplusplus.com ! Tiene una gran documentación sobre las funciones de C / C ++.
  • Consejos generales para las fugas de memoria:
    • Asegúrese de que su memoria asignada dinámicamente se libere.
    • No asignes memoria y olvídate de asignar el puntero.
    • No sobrescriba un puntero con uno nuevo a menos que se libere la memoria antigua.
  • Consejos generales para errores de memoria:
    • Accede y escribe a direcciones e índices que seguro que te pertenecen. Los errores de memoria son diferentes de las fugas; a menudo son solo problemas de tipo IndexOutOfBoundsException .
    • No acceda ni escriba en la memoria después de liberarlo.
  • A veces, Valgrind no siempre señala exactamente dónde está su error. A veces tienes muchos errores y resolver uno de ellos resuelve una cascada de otros.
    • Enumere las funciones en su código que dependen / dependen del código "ofensivo" que tiene el error de memoria. Siga la ejecución del programa (tal vez incluso en gdb tal vez), y busque los errores de condición previa / posterior.
    • Intente comentar el bloque de código "ofensivo" (dentro de lo razonable, de modo que su código aún se compile). Si el error de Valgrind desaparece, has encontrado dónde está.
  • Si todo lo demás falla, intenta buscarlo. ¡Valgrind también tiene documentation !

Una mirada a las fugas y errores comunes

Mira tus punteros

60 bytes in 1 blocks are definitely lost in loss record 1 of 1 at 0x4C2BB78: realloc (vg_replace_malloc.c:785) by 0x4005E4: resizeArray (main.c:12) by 0x40062E: main (main.c:19)

Y el código:

#include <stdlib.h> #include <stdint.h> struct _List { int32_t* data; int32_t length; }; typedef struct _List List; List* resizeArray(List* array) { int32_t* dPtr = array->data; dPtr = realloc(dPtr, 15 * sizeof(int32_t)); //doesn''t update array->data return array; } int main() { List* array = calloc(1, sizeof(List)); array->data = calloc(10, sizeof(int32_t)); array = resizeArray(array); free(array->data); free(array); return 0; }

Como asistente de enseñanza, he visto este error a menudo. El estudiante utiliza una variable local y se olvida de actualizar el puntero original. El error aquí es notar que realloc puede mover la memoria asignada a otro lugar y cambiar la ubicación del puntero. Luego dejamos resizeArray sin decirle a array->data dónde se movió la matriz.

Escritura inválida

1 errors in context 1 of 1: Invalid write of size 1 at 0x4005CA: main (main.c:10) Address 0x51f905a is 0 bytes after a block of size 26 alloc''d at 0x4C2B975: calloc (vg_replace_malloc.c:711) by 0x400593: main (main.c:5)

Y el código:

#include <stdlib.h> #include <stdint.h> int main() { char* alphabet = calloc(26, sizeof(char)); for(uint8_t i = 0; i < 26; i++) { *(alphabet + i) = ''A'' + i; } *(alphabet + 26) = ''/0''; //null-terminate the string? free(alphabet); return 0; }

Observe que Valgrind nos señala la línea de código comentada arriba. La matriz de tamaño 26 está indexada [0,25], por lo que *(alphabet + 26) es una escritura no válida, está fuera de límites. Una escritura no válida es un resultado común de errores off-by-one. Mire el lado izquierdo de su operación de asignación.

Lectura inválida

1 errors in context 1 of 1: Invalid read of size 1 at 0x400602: main (main.c:9) Address 0x51f90ba is 0 bytes after a block of size 26 alloc''d at 0x4C29BE3: malloc (vg_replace_malloc.c:299) by 0x4005E1: main (main.c:6)

Y el código:

#include <stdlib.h> #include <stdint.h> int main() { char* destination = calloc(27, sizeof(char)); char* source = malloc(26 * sizeof(char)); for(uint8_t i = 0; i < 27; i++) { *(destination + i) = *(source + i); //Look at the last iteration. } free(destination); free(source); return 0; }

Valgrind nos señala la línea comentada arriba. Mira la última iteración aquí, que es
*(destination + 26) = *(source + 26); . Sin embargo, *(source + 26) está fuera de límites de nuevo, de manera similar a la escritura no válida. Las lecturas no válidas también son un resultado común de errores off-by-one. Mire el lado derecho de su operación de asignación.

El código abierto (U / Dys) topia

¿Cómo puedo saber cuándo la fuga es mía? ¿Cómo encuentro mi fuga cuando estoy usando el código de otra persona? Encontré una fuga que no es mía; ¿Debo hacer algo? Todas son preguntas legítimas. Primero, 2 ejemplos del mundo real que muestran 2 clases de encuentros comunes.

Jansson : una biblioteca JSON

#include <jansson.h> #include <stdio.h> int main() { char* string = "{ /"key/": /"value/" }"; json_error_t error; json_t* root = json_loads(string, 0, &error); //obtaining a pointer json_t* value = json_object_get(root, "key"); //obtaining a pointer printf("/"%s/" is the value field./n", json_string_value(value)); //use value json_decref(value); //Do I free this pointer? json_decref(root); //What about this one? Does the order matter? return 0; }

Este es un programa simple: lee una cadena JSON y la analiza. En la fabricación, utilizamos las llamadas de la biblioteca para hacer el análisis por nosotros. Jansson hace las asignaciones necesarias dinámicamente ya que JSON puede contener estructuras anidadas de sí mismo. Sin embargo, esto no significa que decref o " decref " la memoria que se nos da de cada función. De hecho, este código que escribí anteriormente arroja una "Lectura no válida" y una "Escritura no válida". Esos errores desaparecen cuando se saca la línea de decref por value .

¿Por qué? El value variable se considera una "referencia prestada" en la API de Jansson. Jansson realiza un seguimiento de su memoria para usted, y simplemente tiene que decref estructuras JSON de forma independiente. La lección aquí: leer la documentación . De Verdad. A veces es difícil de entender, pero te están diciendo por qué suceden estas cosas. En su lugar, tenemos preguntas existentes sobre este error de memoria.

SDL : una librería de gráficos y juegos.

#include "SDL2/SDL.h" int main(int argc, char* argv[]) { if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) != 0) { SDL_Log("Unable to initialize SDL: %s", SDL_GetError()); return 1; } SDL_Quit(); return 0; }

¿Qué hay de malo con este código ? Se fuga constantemente ~ 212 KiB de memoria para mí. Tómate un momento para pensarlo. Encendemos y apagamos SDL. ¿Responder? No hay nada malo.

Eso puede sonar extraño al principio . A decir verdad, los gráficos son desordenados y, a veces, hay que aceptar algunas filtraciones como parte de la biblioteca estándar. La lección aquí: no necesitas calmar cada pérdida de memoria . A veces solo necesitas suprimir las fugas porque son problemas conocidos de los que no puedes hacer nada . (¡Este no es mi permiso para ignorar tus propias fugas!)

Respuestas al vacío

¿Cómo puedo saber cuándo la fuga es mía?
Es. (99% seguro, de todos modos)

¿Cómo encuentro mi fuga cuando estoy usando el código de otra persona?
Es probable que alguien más lo haya encontrado. Prueba Google! Si eso falla, usa las habilidades que te di anteriormente. Si eso falla y la mayoría de las veces se ven llamadas a la API y poco de su propio seguimiento de pila, vea la siguiente pregunta.

Encontré una fuga que no es mía; ¿Debo hacer algo?
¡Sí! La mayoría de las API tienen formas de reportar errores y problemas. ¡Usalos, usalos a ellos! ¡Ayuda a devolver las herramientas que estás usando en tu proyecto!

Otras lecturas

Gracias por quedarte conmigo todo este tiempo. Espero que hayas aprendido algo, mientras intentaba atender al amplio espectro de personas que llegan a esta respuesta. Algunas cosas que espero que haya preguntado en el camino: ¿Cómo funciona el asignador de memoria de C? ¿Qué es realmente una pérdida de memoria y un error de memoria? ¿Cómo son diferentes de segfaults? ¿Cómo funciona Valgrind? Si tienes alguno de estos, alimenta tu curiosidad:


Prueba esto:

valgrind --leak-check=full -v ./your_program

Mientras se instale valgrind, pasará por tu programa y te dirá lo que está mal. Puede darle indicaciones y lugares aproximados donde se pueden encontrar las fugas. Si estás haciendo un defecto, intenta ejecutarlo a través de gdb .


Tu puedes correr:

valgrind --leak-check=full --log-file="logfile.out" -v [your_program(and its arguments)]