Problema de uso de memoria en C
Pregunta
Por favor ayuda :) OS:linux
Donde en "sleep(1000);", en este momento "top (mostrar tareas de Linux)" me escribió un 7,7% de uso de MEM.valgrind:pérdida de memoria no encontrada.
Lo entiendo, escribí correctamente y todos los resultados de malloc son NULL.Pero, ¿por qué en este tiempo "dormir" mi programa NO disminuyó la memoria?¿Qué falta?
Perdón por mi mal inglés, gracias.
~ # tmp_soft
For : Is it free?? no
Is it free?? yes
For 0
For : Is it free?? no
Is it free?? yes
For 1
END : Is it free?? yes
END
~ #top
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
23060 root 20 0 155m 153m 448 S 0 7.7 0:01.07 tmp_soft
Fuente completa:tmp_soft.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
struct cache_db_s
{
int table_update;
struct cache_db_s * p_next;
};
void free_cache_db (struct cache_db_s ** cache_db)
{
struct cache_db_s * cache_db_t;
while (*cache_db != NULL)
{
cache_db_t = *cache_db;
*cache_db = (*cache_db)->p_next;
free(cache_db_t);
cache_db_t = NULL;
}
printf("Is it free?? %s\n",*cache_db==NULL?"yes":"no");
}
void make_cache_db (struct cache_db_s ** cache_db)
{
struct cache_db_s * cache_db_t = NULL;
int n = 10000000;
for (int i=0; i = n; i++)
{
if ((cache_db_t=malloc(sizeof(struct cache_db_s)))==NULL) {
printf("Error : malloc 1 -> cache_db_s (no free memory) \n");
break;
}
memset(cache_db_t, 0, sizeof(struct cache_db_s));
cache_db_t->table_update = 1; // tmp
cache_db_t->p_next = *cache_db;
*cache_db = cache_db_t;
cache_db_t = NULL;
}
}
int main(int argc, char **argv)
{
struct cache_db_s * cache_db = NULL;
for (int ii=0; ii 2; ii++) {
make_cache_db(&cache_db);
printf("For : Is it free?? %s\n",cache_db==NULL?"yes":"no");
free_cache_db(&cache_db);
printf("For %d \n", ii);
}
printf("END : Is it free?? %s\n",cache_db==NULL?"yes":"no");
printf("END \n");
sleep(1000);
return 0;
}
Solución
Si está intentando establecer si su programa tiene una pérdida de memoria, entonces top
no es la herramienta adecuada para el trabajo (valrind
es).
top
muestra el uso de la memoria tal como lo ve el sistema operativo.Incluso si llamas free
, no hay garantía de que la memoria liberada se devuelva al sistema operativo.Normalmente, no sería así.No obstante, la memoria se vuelve "libre" en el sentido de que su proceso puede usarla para asignaciones posteriores.
editar Si tu libc
lo admite, podrías intentar experimentar con M_TRIM_THRESHOLD
.Incluso si sigue este camino, será complicado (un solo bloque usado ubicado cerca de la parte superior del montón evitaría que toda la memoria libre debajo de él se libere al sistema operativo).
Otros consejos
Por buenas razones, prácticamente ningún problema de memoria devuelve los bloques al sistema operativo
La memoria solo se puede eliminar de su programa en unidades de páginas, e incluso a eso es poco probable que se observe.
Calloc (3) y malloc (3) interactúan con el kernel para obtener memoria, si es necesario. Pero muy, muy pocas implementaciones de la memoria gratuita (3) de la historia, de alguna vez devolver el kernel 1 , simplemente lo agregan a una lista gratuita que Calloc () y Malloc () consultarán más adelante para reutilizar el Bloques liberados. Hay buenas razones para este enfoque de diseño.
Incluso si es gratuito () quería devolver la memoria al sistema, necesitaría al menos una página de memoria contigua para que el kernel proteja realmente a la región, así que la liberación de un bloque pequeño solo conduciría a un cambio de protección. Si fue el bloque pequeño Último en una página.
Teoría de la Operación
SO MALLOC (3) obtiene memoria del kernel cuando lo necesita, en última instancia, en unidades de múltiplos de página discretos. Estas páginas están divididas o consolidadas como lo requiere el programa. Malloc y cooperar gratis para mantener un directorio. Conectan bloques libres adyacentes cuando son posibles para poder proporcionar grandes bloques. El directorio puede o no puede implicar el uso de la memoria en bloques liberados para formar una lista vinculada. (La alternativa es un poco más de memoria compartida y amigable con las hojas, e implica asignar memoria específicamente para el directorio). MALLOC y LIBRES tienen poco si la capacidad de hacer cumplir el acceso a bloques individuales incluso cuando se compila el código especial y opcional de depuración. el programa.
1. El hecho de que muy pocas implementaciones de libre () intento de devolver la memoria al sistema no se deben en absoluto a los implementadores que se aflojan.
interactuando con el kernel es mucho más lento que Simplemente ejecutando el código de la biblioteca, y el beneficio sería pequeño. La mayoría de los programas tienen una huella de memoria de estado estable o en estado, por lo que el tiempo dedicado al analizar el montón que busca la memoria retornable se desperdiciaría completamente. Otras razones incluyen el hecho de que la fragmentación interna hace que existan bloques alineados por la página, y es probable que la devolución de un bloque se bloquee a ambos lados. Finalmente, es probable que los pocos programas que devuelven grandes cantidades de memoria.
Generalmente libre () no devuelve la memoria física a OS, todavía están asignados en la memoria virtual de su proceso.Si asigna un gran trozo de memoria, LIBC puede asignarlo por MMAP ();Luego, si lo libero, LIBC puede liberar la memoria a OS por MUNMAP (), en este caso, la parte superior mostrará que su uso de memoria se reduce.
Por lo tanto, si no desea liberar la memoria a SO explícitamente, puede usar MMAP () / MUNMAP ().
Cuando usted free()
memoria, se devuelve al grupo de memoria de la biblioteca C estándar y no al sistema operativo.En la visión del sistema operativo, tal como lo ves a través top
, el proceso todavía está "usando" esta memoria.Dentro del proceso, la biblioteca C ha tenido en cuenta la memoria y podría devolver el mismo puntero desde malloc()
en el futuro.
Lo explicaré un poco más con un comienzo diferente:
Durante sus llamadas a malloc
, la implementación de la biblioteca estándar puede determinar que el proceso no tiene suficiente memoria asignada por parte del sistema operativo.En ese momento, la biblioteca realizará una llamada al sistema para recibir más memoria del sistema operativo para el proceso (por ejemplo, sbrk()
o VirtualAlloc()
llamadas al sistema en Unix o Windows, respectivamente).
Después de que la biblioteca solicita memoria adicional del sistema operativo, agrega esta memoria a su estructura de memoria disponible para regresar. malloc
.Llamadas posteriores a malloc
utilizará esta memoria hasta que se agote.Luego, la biblioteca le pide al sistema operativo aún más memoria.
Cuando usted free
memoria, la biblioteca generalmente no devuelve la memoria al sistema operativo.Hay muchas razones para esto.Una razón es que el autor de la biblioteca creía que llamarías malloc
de nuevo.Si no llamas malloc
Nuevamente, su programa probablemente terminará pronto.En cualquier caso, no hay mucha ventaja en devolver la memoria al sistema operativo.
Otra razón por la que es posible que la biblioteca no devuelva la memoria al sistema operativo es que la memoria del sistema operativo está asignada en rangos grandes y contiguos.Solo se puede devolver cuando un rango contiguo completo ya no esté en uso.El patrón de llamada malloc
y free
Es posible que no borre todo el rango de uso.
Dos problemas:
En
make_cache_db()
, la líneafor (int i=0; i = n; i++)
probablemente debería leer
for (int i=0; i<n; i++)
De lo contrario, solo asignarás una única
cache_db_s
nodo.La forma en que estás asignando
cache_db
enmake_cache_db()
parece tener errores.Parece que su intención es devolver un puntero al primer elemento de la lista vinculada;pero porque estás reasignandocache_db
En cada iteración del bucle, terminarás devolviendo un puntero al último elemento de la lista.Si luego libera la lista usando
free_cache_db()
, esto hará que pierda memoria.Por el momento, sin embargo, este problema está enmascarado por el error descrito en el punto anterior, que hace que usted asigne listas de solo longitud 1.
Independientemente de estos errores, el punto planteado por aix es muy válido:La biblioteca en tiempo de ejecución no necesita devolver todos free()
d memoria al sistema operativo.