Fuga todavía alcanzable detectada por Valgrind

7 minutos de lectura

Todas las funciones mencionadas en este bloque son funciones de biblioteca. ¿Cómo puedo corregir esta pérdida de memoria?

Está listado bajo el “Todavía accesiblecategoría “. (Hay 4 más, que son muy similares, pero de diferentes tamaños)

 630 bytes in 1 blocks are still reachable in loss record 5 of 5
    at 0x4004F1B: calloc (vg_replace_malloc.c:418)
    by 0x931CD2: _dl_new_object (dl-object.c:52)
    by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972)
    by 0x92EFB6: _dl_map_object (dl-load.c:2251)
    by 0x939F1B: dl_open_worker (dl-open.c:255)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0x9399C5: _dl_open (dl-open.c:584)
    by 0xA64E31: do_dlopen (dl-libc.c:86)
    by 0x935965: _dl_catch_error (dl-error.c:178)
    by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47)
    by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53)
    by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)

Captura: Una vez que ejecuté mi programa, no hubo pérdidas de memoria, pero tenía una línea adicional en la salida de Valgrind, que no estaba presente antes:

Descartar sims en 0x5296fa0-0x52af438 en /lib/libgcc_s-4.4.4-20100630.so.1 debido a munmap()

Si la fuga no se puede rectificar, ¿alguien puede al menos explicar por qué la línea munmap () hace que Valgrind informe 0 fugas “todavía accesibles”?

Editar:

Aquí hay una muestra de prueba mínima:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *runner(void *param) {
    /* some operations ... */
    pthread_exit(NULL);
}

int n;

int main(void) {

    int i;
    pthread_t *threadIdArray;

    n=10; /* for example */

    threadIdArray = malloc((n+n-1)*sizeof(pthread_t));  

    for(i=0;i<(n+n-1);i++) {
        if( pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0 ) {
            printf("Couldn't create thread %d\n",i);
            exit(1);
        }
    }


    for(i=0;i<(n+n-1);i++) {
        pthread_join(threadIdArray[i],NULL);
    }

    free(threadIdArray);

    return(0);
}

Corre con:

valgrind -v --leak-check=full --show-reachable=yes ./a.out

Hay más de una forma de definir “pérdida de memoria”. En particular, hay dos definiciones principales de “pérdida de memoria” que son de uso común entre los programadores.

La primera definición comúnmente utilizada de “pérdida de memoria” es: “Se asignó memoria y no se liberó posteriormente antes de que finalizara el programa”. Sin embargo, muchos programadores (con razón) argumentan que ciertos tipos de fugas de memoria que se ajustan a esta definición en realidad no plantean ningún tipo de problema y, por lo tanto, no deben considerarse verdadero “pérdidas de memoria”.

Podría decirse que una definición más estricta (y más útil) de “pérdida de memoria” es “La memoria se asignó y no poder ser liberado posteriormente porque el programa ya no tiene punteros al bloque de memoria asignado”. En otras palabras, no puede liberar memoria a la que ya no tiene punteros. Por lo tanto, dicha memoria es una “pérdida de memoria”. Valgrind usa esta definición más estricta del término “fuga de memoria”. Este es el tipo de fuga que potencialmente puede causar un agotamiento significativo del almacenamiento dinámico, especialmente para procesos de larga duración.

La categoría “todavía accesible” dentro del informe de fugas de Valgrind se refiere a las asignaciones que se ajustan solo a la primera definición de “fuga de memoria”. Estos bloques no se liberaron, pero se podrían haber liberado (si el programador lo hubiera querido) porque el programa todavía seguía la pista de los punteros a esos bloques de memoria.

En general, no hay necesidad de preocuparse por los bloques “todavía accesibles”. No plantean el tipo de problema que verdadero las fugas de memoria pueden causar. Por ejemplo, normalmente no hay potencial para el agotamiento del montón de bloques “todavía accesibles”. Esto se debe a que estos bloques suelen ser asignaciones únicas, cuyas referencias se mantienen a lo largo de la duración del proceso. Si bien puede revisar y asegurarse de que su programa se libere todos memoria asignada, por lo general no hay ningún beneficio práctico al hacerlo, ya que el sistema operativo recuperará toda la memoria del proceso después de que finalice, de todos modos. Contrasta esto con verdadero fugas de memoria que, si no se solucionan, podrían hacer que un proceso se quede sin memoria si se deja en ejecución el tiempo suficiente, o simplemente provocará que un proceso consuma mucha más memoria de la necesaria.

Probablemente, la única vez que es útil asegurarse de que todas las asignaciones tengan “libres” coincidentes es si sus herramientas de detección de fugas no pueden decir qué bloques son “aún accesibles” (pero Valgrind puede hacerlo) o si su sistema operativo no recupera todos la memoria de un proceso de terminación (todas las plataformas que Valgrind ha sido portado para hacer esto).

  • ¿Puedes suponer qué está haciendo munmap() que hace que desaparezcan los bloques “todavía accesibles”?

    usuario191776

    4 oct 2010 a las 18:38


  • @crypto: Podría ser eso munmap se invoca como resultado de la descarga de un objeto compartido. Y todos los recursos utilizados por el objeto compartido podrían liberarse antes de que se descargue. Esto podría explicar por qué los “todavía accesibles” se están liberando en el munmap caso. Sin embargo, solo estoy especulando aquí. No hay suficiente información aquí para decir con seguridad.

    – Moldeado Dan

    4 oct 2010 a las 19:11

  • Un caso en el que la memoria “todavía accesible” puede considerarse una pérdida de memoria: suponga que tiene una tabla hash en la que agrega punteros a la memoria asignada del montón como valor. Si continúa insertando nuevas entradas en la tabla, pero no elimina y libera las que ya no necesita, puede crecer indefinidamente, filtrando el evento de la memoria del montón si esa memoria es técnicamente “todavía accesible”. Este es el caso de pérdida de memoria que puede tener en Java u otros lenguajes de recolección de basura.

    – lvella

    25/06/2015 a las 18:50

  • Consulte también esta respuesta en las preguntas frecuentes de valgrind sobre los bloques “todavía accesibles” creados por STL. valgrind.org/docs/manual/faq.html#faq.informes

    – John Perry

    14/06/2016 a las 21:16

  • “muchos programadores (con razón) argumentan que [leaked memory] en realidad no poses [a] problema y, por lo tanto, no deben considerarse verdaderas fugas de memoria” – Lol… Cree una DLL nativa con ese tipo de pérdida de memoria, y luego haga que Java o .Net la consuman. Java y .Net cargan y descargan archivos DLL miles de veces durante la vida útil de un programa. Cada vez que se recarga la DLL, perderá un poco más de memoria. Los programas de ejecución prolongada eventualmente se quedarán sin memoria. Vuelve loco al mantenedor OpenJDK de Debian. Dijo lo mismo en la lista de correo de OpenSSL mientras discutíamos las fugas de memoria “benignas” de OpenSSL.

    – jww

    23 de agosto de 2018 a las 16:20


avatar de usuario
Jens Gustedt

Dado que hay alguna rutina de la familia pthread en la parte inferior (pero no conozco esa en particular), supongo que ha lanzado algún hilo como unible que ha terminado la ejecución.

La información del estado de salida de ese subproceso se mantiene disponible hasta que llame pthread_join. Por lo tanto, la memoria se mantiene en un registro de pérdida al finalizar el programa, pero aún es accesible ya que podría usar pthread_join para acceder a ella.

Si este análisis es correcto, inicie estos subprocesos separados o únase a ellos antes de finalizar su programa.

Editar: ejecuté su programa de muestra (después de algunas correcciones obvias) y no tengo errores, pero los siguientes

==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933-- 
--18933-- used_suppression:      2 dl-hack3-cond-1
--18933-- used_suppression:      2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a

Desde el dl- la cosa se parece mucho a lo que ves, supongo que ves un problema conocido que tiene una solución en términos de un archivo de supresión para valgrind. Tal vez su sistema no esté actualizado o su distribución no mantenga estas cosas. (El mío es ubuntu 10.4, 64 bits)

  • Estoy recibiendo 0 errores al igual que usted. Consulte el resumen de fugas para obtener información sobre las “fugas”.

    usuario191776

    5 de octubre de 2010 a las 6:16

  • @crypto: no entiendo. ¿Quieres decir que tienes las mismas supresiones que yo?

    – Jens Gusted

    5 de octubre de 2010 a las 7:11

  • used_suppression: 14 dl-hack3-cond-1 <- eso es lo que obtengo

    usuario191776

    5 de octubre de 2010 a las 8:14

Aquí hay una explicación adecuada de “todavía accesible”:

“Aún accesible” son fugas asignadas a variables globales y estáticas-locales. Debido a que valgrind realiza un seguimiento de las variables globales y estáticas, puede excluir las asignaciones de memoria que se asignan “una vez y se olvida”. Una variable global a la que se le asignó una asignación una vez y nunca se reasignó esa asignación no suele ser una “fuga” en el sentido de que no crece indefinidamente. Sigue siendo una fuga en sentido estricto, pero por lo general se puede ignorar a menos que seas pedante.

Las variables locales a las que se asignan asignaciones y no se liberan casi siempre son fugas.

Aquí hay un ejemplo

int foo(void)
{
    static char *working_buf = NULL;
    char *temp_buf;
    if (!working_buf) {
         working_buf = (char *) malloc(16 * 1024);
    }
    temp_buf = (char *) malloc(5 * 1024);

    ....
    ....
    ....

}

Valgrind informará working_buf como “todavía accesible – 16k” y temp_buf como “definitivamente perdido – 5k”.

No pareces entender lo que still reachable significa.

Cualquier cosa still reachable es no una fuga. No necesitas hacer nada al respecto.

Para futuros lectores, “Aún accesible” podría significar que se olvidó de cerrar algo como un archivo. Si bien no parece así en la pregunta original, siempre debe asegurarse de haberlo hecho.

  • Valgrind solo informa descriptores de archivos filtrados con --track-fds=yes. No se informarán como “aún accesibles”.

    – ZachB

    15 de diciembre de 2020 a las 0:30

  • Bueno, si se abrió con fopenentonces la fuga será para el FILE estructura

    – syockit

    5 de enero de 2021 a las 2:28

  • Valgrind solo informa descriptores de archivos filtrados con --track-fds=yes. No se informarán como “aún accesibles”.

    – ZachB

    15 de diciembre de 2020 a las 0:30

  • Bueno, si se abrió con fopenentonces la fuga será para el FILE estructura

    – syockit

    5 de enero de 2021 a las 2:28

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad