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).

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)
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.
Preguntas frecuentes sobre Valgrind.
– jww
23 de agosto de 2018 a las 17:40