Digamos que tengo el siguiente código C:
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
Cuando compilo y ejecuto ese programa en C, es decir, después de asignar algo de espacio en la memoria, ¿la memoria que asigné todavía se asignará (es decir, básicamente ocupará espacio) después de salir de la aplicación y el proceso finalice?
c
memory-management
Andreas Grech
fuente
fuente
Respuestas:
Depende del sistema operativo. La mayoría de los sistemas operativos modernos (y todos los principales) liberarán memoria no liberada por el programa cuando finalice.
Confiar en esto es una mala práctica y es mejor liberarlo explícitamente. El problema no es solo que su código se vea mal. Puede decidir que desea integrar su pequeño programa en uno más grande y de larga duración. Luego, un tiempo después, tendrás que pasar horas rastreando las pérdidas de memoria.
Confiar en una característica de un sistema operativo también hace que el código sea menos portátil.
fuente
En general, los sistemas operativos modernos de uso general se limpian después de los procesos terminados . Esto es necesario porque la alternativa es que el sistema pierda recursos con el tiempo y requiera reiniciar debido a programas que están mal escritos o simplemente tienen errores que ocurren raramente y que pierden recursos.
Hacer que su programa libere explícitamente sus recursos de todos modos puede ser una buena práctica por varias razones, como:
Sin embargo, aquí hay una razón para omitir la liberación de memoria: apagado eficiente . Por ejemplo, suponga que su aplicación contiene una gran memoria caché. Si cuando sale, pasa por toda la estructura de la caché y la libera una pieza a la vez, no tiene ningún propósito útil y desperdicia recursos. Especialmente, considere el caso en el que el sistema operativo ha intercambiado las páginas de memoria que contienen su caché al disco; Al recorrer la estructura y liberarla, recupera todas esas páginas a la vez , desperdicia una cantidad significativa de tiempo y energía sin ningún beneficio real, ¡y posiblemente incluso haga que otros programas del sistema se intercambien!
Como ejemplo relacionado, existen servidores de alto rendimiento que funcionan creando un proceso para cada solicitud y luego haciéndolo salir cuando termina; de esta manera, ni siquiera tienen que rastrear la asignación de memoria , y nunca realizar ninguna liberación o recolección de basura, ya que todo simplemente desaparece en la memoria libre del sistema operativo al final del proceso. (Se puede hacer el mismo tipo de cosas dentro de un proceso utilizando un asignador de memoria personalizado, pero requiere una programación muy cuidadosa; esencialmente, hacer la propia noción de "procesos ligeros" dentro del proceso del sistema operativo).
fuente
Mis disculpas por publicar tanto tiempo después de la última publicación en este hilo.
Un punto adicional. No todos los programas logran salidas agradables. Los bloqueos y ctrl-C, etc. harán que un programa se cierre de manera incontrolada. Si su sistema operativo no libera su montón, limpia su pila, elimina variables estáticas, etc., eventualmente colapsará su sistema por pérdidas de memoria o algo peor.
Aparte de esto, es interesante que las fallas / fallas en Ubuntu, y sospecho que todos los demás sistemas operativos modernos, tienen problemas con los recursos "manejados". Los sockets, archivos, dispositivos, etc. pueden permanecer "abiertos" cuando un programa finaliza / falla. También es una buena práctica cerrar cualquier cosa con un "identificador" o "descriptor" como parte de su limpieza antes de la salida elegante.
Actualmente estoy desarrollando un programa que usa sockets en gran medida. Cuando me quedo atascado en un bloqueo, tengo que hacer Ctrl-C fuera de él, por lo tanto, encallando mis enchufes. Agregué un std :: vector para recopilar una lista de todos los sockets abiertos y un controlador sigaction que captura sigint y sigterm. El controlador recorre la lista y cierra los sockets. Planeo hacer una rutina de limpieza similar para usar antes de los lanzamientos que conducirán a la terminación prematura.
¿Alguien quiere comentar sobre este diseño?
fuente
Lo que está sucediendo aquí ( en un sistema operativo moderno ) es que su programa se ejecuta dentro de su propio "proceso". Esta es una entidad del sistema operativo que está dotada de su propio espacio de direcciones, descriptores de archivos, etc.
malloc
llamadas están asignando memoria del "montón" o páginas de memoria no asignadas que están asignadas a su proceso.Cuando su programa finaliza, como en este ejemplo, todos los recursos asignados a su proceso son simplemente reciclados / destruidos por el sistema operativo. En el caso de la memoria, todas las páginas de memoria que se le asignan simplemente se marcan como "libres" y se reciclan para el uso de otros procesos. Las páginas son un concepto de nivel inferior al que maneja malloc; como resultado, los detalles de malloc / free simplemente se eliminan a medida que se limpia todo.
Es el equivalente moral de, cuando haya terminado de usar su computadora portátil y quiera dársela a un amigo, no se moleste en eliminar individualmente cada archivo. Simplemente formatee el disco duro.
Dicho todo esto, como señalan todos los demás respondedores, confiar en esto no es una buena práctica:
fuente
Si. El sistema operativo limpia los recursos. Bueno ... las versiones antiguas de NetWare no lo hicieron.
Editar: Como señaló San Jacinto, ciertamente hay sistemas (aparte de NetWare) que no hacen eso. Incluso en los programas desechables, trato de tener el hábito de liberar todos los recursos solo para mantener el hábito.
fuente
Sí, el sistema operativo libera toda la memoria cuando finaliza el proceso.
fuente
malloc
solo puedo prometer lo que C hará con la memoria; por diseño, C no garantiza mucho de nada con respecto al comportamiento fuera de C mismo. Si la aplicación muere inesperadamente, cualquier promesa hecha por la biblioteca en tiempo de ejecución es nula y sin efecto, ya que ya no está viva para cumplirla.Depende, los sistemas operativos generalmente lo limpiarán por usted, pero si está trabajando, por ejemplo, en software integrado, es posible que no se publique.
Solo asegúrese de liberarlo, puede ahorrarle mucho tiempo más adelante, cuando desee integrarlo en un proyecto grande.
fuente
Eso realmente depende del sistema operativo, pero para todos los sistemas operativos que encontrará, la asignación de memoria desaparecerá cuando finalice el proceso.
fuente
Creo que la liberación directa es lo mejor. El comportamiento indefinido es lo peor, por lo que si tiene acceso mientras aún está definido en su proceso, hágalo, hay muchas buenas razones que la gente ha dado para ello.
En cuanto a dónde, o si, encontré eso en W98, la verdadera pregunta era 'cuándo' (no vi una publicación que enfatice esto). Un pequeño programa de plantilla (para entrada MIDI SysEx, usando varios espacios malloc'd) liberaría memoria en el bit WM_DESTROY del WndProc, pero cuando trasplante esto a un programa más grande, se bloqueó al salir. Supuse que esto significaba que estaba tratando de liberar lo que el sistema operativo ya había liberado durante una limpieza más grande. Si lo hice en WM_CLOSE, luego llamé a DestroyWindow (), todo funcionó bien, salida limpia instantánea.
Si bien esto no es exactamente lo mismo que los búferes MIDI, hay una similitud en que es mejor mantener el proceso intacto, limpiar completamente y luego salir. Con trozos de memoria modestos, esto es muy rápido. Descubrí que muchos búferes pequeños funcionaban más rápido en operación y limpieza que pocos grandes.
Pueden existir excepciones, como dijo alguien al evitar extraer grandes trozos de memoria de un archivo de intercambio en el disco, pero incluso eso puede minimizarse manteniendo más espacios asignados y más pequeños.
fuente