2010-12-02 8 views
6

Por lo que entiendo porque malloc asigna dinámicamente mem, necesita liberar esa memoria para poder usarla nuevamente.¿Tiene que liberarse cada llamada malloc?

  1. ¿Qué pasa si usted devuelve un char * que se creó utilizando malloc (es decir, ¿cómo se supone para liberar eso)
  2. Si deja el puntero como es y salir de la aplicación será liberados . (No puedo encontrar una respuesta definitiva sobre esto, algunos dicen que sí, algunos dicen que no).
+0

No encontrará una respuesta definitiva sobre lo que debe hacer, pero hay respuestas definitivas sobre lo que debe hacer el estándar (no importa) y todos los sistemas operativos del mundo real (incluso DOS - tampoco le importa). Los sistemas embebidos que realmente les importan probablemente ni siquiera tengan un concepto de 'exit()', pero estoy seguro de que alguien se pondrá en pie para demostrarme que estoy equivocado. :-) –

Respuesta

6
  1. La persona que llama tiene que liberarla (o los arreglos para que pueda ser liberado). Esto significa que las funciones que crean y devuelven recursos deben documentar exactamente cómo debería liberarse.

  2. La mayoría de los sistemas operativos liberarán la memoria cuando finalice el programa, como parte de la definición de "proceso". Al estándar C no le importa lo que sucede, está más allá del alcance del programa. No todos los sistemas operativos tienen una abstracción completa del proceso, pero sí lo hacen los sistemas operativos de escritorio.

Las principales razones para liberarla antes de eso son:

  • Si la memoria libre tan pronto como sea posible, a menudo mucho tiempo antes de salida del proceso, el programa usa menos memoria total.
  • Si no lo libera, y luego desea cambiar su programa a una rutina dentro de otro programa, que quizás se llame muchas veces, de repente necesita mucha más memoria que antes (fuga de memoria).
  • Existen herramientas de depuración que lo ayudarán a identificar fugas de memoria, advirtiéndole acerca de la memoria que todavía se asigna cuando el programa finaliza. Estos realmente no ayudan mucho si hay un montón de basura filtrada deliberadamente a través.
  • Si no lo libera y tiene algún problema, es mucho más difícil volver más tarde y encontrar toda la memoria que necesita liberarse, que hacerlo desde el principio.
  • Hay tantos casos en los que necesita liberar la memoria (para evitar el uso de gran cantidad de memoria en programas de larga ejecución), que su estrategia predeterminada debe ser limpiar todo.

Las razones vagamente plausibles no libre son:

  • menos código.
  • Si tiene millones de bloques para liberar de forma individual, inmediatamente antes de la salida del programa, entonces podría ser mucho más rápido dejar que el sistema operativo caiga todo el proceso.
  • Las cosas creadas a pedido y almacenadas en forma global pueden ser bastante difíciles de limpiar de forma segura, si no se sabe exactamente dónde se usan. Piense en algún tipo de caché que se rellene a medida que avanza, que podría tener reglas MRU para limitar la cantidad de memoria que ocupa, por lo que no se trata de una fuga ilimitada. OK, entonces esto es algo malo (globales sin restricciones) que causa otra cosa mala (memoria no actualizada), pero vale la pena conocerla como una razón por la que es posible que veas bloqueos no actualizados en el código existente, y no necesariamente puedes entrar y arreglarlo ellos.

Las razones para la liberación casi siempre superan las razones en contra.

+0

La única razón por la que acepté esta respuesta es porque se propuso un enfoque alternativo para devolver un puntero. No hay nada de malo en ninguna de las otras respuestas – RC1140

+0

También lo entiendo, si no liberas memoria, la dejas abierta para ser explotada, especialmente si estás asignando más memoria y luego usando. https://en.wikipedia.org/wiki/Buffer_overflow#Heap-based_exploitation – Caperneoignis

3

Sí. Si malloc, necesita liberar. Está garantizando fugas de memoria mientras su programa se está ejecutando si no está libre.

Free it.

Siempre.

Período.

+1

+1 Siempre es una buena práctica. No hay excepciones Puede omitirlo si el programa termina. ¿Qué pasa con los procesos del servidor, que normalmente no terminan? No adquiera el hábito de pensar que las filtraciones están bien. – EvilTeach

2

Sí, cada llamada a malloc() tiene que coincidir con una llamada al free().

Para responder a sus preguntas específicas:

  1. Hay que documentar de forma explícita su API que indica al usuario si el puntero devuelto tiene que ser free() 'd
  2. El sistema operativo liberará toda la memoria asignada al proceso.
+1

@Software Monkey, esos no son números GNU, sino secciones manuales de Unix, consulte http://en.wikipedia.org/wiki/Man_page, pero lo que sea. –

+0

¿Qué se supone que es un "número Gnu"? –

+0

Sean lo que sean, no pertenecen a este contexto. Pero puede devolverlos si cree que proporcionan algún beneficio. –

0

1) La misma manera en que se libera la memoria normalmente, es decir

p = func(); 
//... 
free(p); 

El truco está en asegurarse de que siempre lo haces ...

2) En términos generales, sí. Pero aún debes liberar cualquier memoria que utilices como buena práctica. No gastar el tiempo para descubrir dónde liberar la memoria es solo ser flojo.

6
  1. Si usted tiene un puntero a la memoria creado por malloc, free ing que la memoria, usando ese puntero, va a hacer lo correcto. Sí, hay algo de magia involucrado; esto será resuelto por tu compilador.

  2. Sí, si ignora la liberación de memoria y sale de la aplicación, el sistema operativo liberará la memoria. Sin embargo, se considera una mala práctica dejarlo sin refrigeración. El sistema operativo puede no hacer lo correcto (especialmente en configuraciones integradas), o puede que no lo haga de manera oportuna. Además, si está ejecutando su programa continuamente, puede terminar consumiendo una cantidad creciente de memoria, eventualmente consumiéndolo todo y quedándose sin memoria y fallando.

0

Tomemos los un punto a la vez ...

  1. Si devuelve un char * que sabes fue creado con malloc, entonces sí, es su responsabilidad para liberar a eso. Puede hacerlo con free(myCharPtr).

  2. El sistema operativo recuperará la memoria, y no se perderá para siempre, pero técnicamente no hay garantía de que se recuperará justo cuando la aplicación fallezca. Eso solo depende del sistema operativo.

2

Si se escribe la función de sí mismo: evitar hacerlo.

  • En lugar de eso, deje que la persona que llama pase un búfer, permita que la persona que llama especifique el tamaño del búfer y copie los datos en ese búfer. De esta forma, puede usar su función desde otros módulos que no usan el mismo montón (otros lenguajes de programación, tiempo de ejecución de C diferente)
  • Si por alguna razón no puede usar dicha interfaz, especifique en la función documentación que la persona que llama tiene que liberar el puntero devuelto después de que haya terminado con él.

Si está utilizando una función de biblioteca: Eche un vistazo a la documentación.

  • Si la documentación indica que debe liberar, hágalo.
  • Si la documentación indica que no es necesario, puede ser una función de limpieza global que deba invocarse para liberar los recursos del módulo.

En cuanto a su segunda pregunta, liberando antes de salir se recomienda. Técnicamente no dolerá, pero cuando quieras reutilizar tu código en un proyecto más grande, estarás agradecido de haber escrito la limpieza correcta en primer lugar.

+0

si no es demasiado inconveniente, ¿puede proporcionar un ejemplo de su primer punto de viñeta? es decir, "dejar que el que llama pase un búfer" – Abdul

+1

Un ejemplo sería la función [snprintf] (http://www.cplusplus.com/reference/cstdio/snprintf/). El primer parámetro es un puntero a un buffer que debe ser llenado por la función, el segundo argumento especifica la longitud de este buffer. – Timbo

0

No iría tan lejos como para decir que cada malloc debe ser liberado, pero yo diría que, no importa cuánto tiempo se ejecute un programa, debe haber un número limitado de asignaciones (y tamaño total) que ganó ' ser liberado No es necesario que el número sea una constante estática, pero debe poder especificarse en términos de otra cosa (por ejemplo, este programa procesa widgets, sino que asignará una estructura de 64 bytes para cada cuestionario en el widget más grande). Es posible que uno no sepa de antemano el tamaño del widget más grande, pero si, por ejemplo, uno sabe que el almacenamiento temporal requerido para procesar un widget es proporcional al cuadrado de su tamaño, se podría inferir con seguridad que el widget más grande será lo suficientemente pequeño como para que la cantidad total de memoria sea muy pequeña.

0

El estándar C no tiene ningún concepto del entorno del sistema fuera de la ejecución de un solo programa, por lo que no puede especificar qué sucede "después de que el programa finalice". Al mismo tiempo, en ningún lugar exige que la memoria obtenida con malloc se deba o deba liberarse con free antes de una llamada al exit o un retorno desde main, y creo que está bastante claro que la intención es salir sin liberar manualmente la memoria no dejará los recursos atados, al igual que la llamada al exit sin cerrar todos los archivos primero los cierra automáticamente (incluido el enjuagarlos).

Ahora, en cuanto a si se debe o no debe llamada free, que depende mucho de su programa en particular.

  • Cualquier biblioteca de códigos debe free cualquier memoria que se obtiene exclusivamente para uso interno tan pronto como sea posible.
  • Una biblioteca que devuelve objetos asignados al programa de llamada siempre debe proporcionar una llamada correspondiente para liberar esos objetos.
  • Una biblioteca que realiza asignaciones como parte de una inicialización global (nota: este es un diseño muy malo, pero a veces inevitable) debería proporcionar una forma para que la aplicación invierta esa inicialización y libere todo lo que se asignó. Esto es especialmente importante si la biblioteca puede ser cargada dinámicamente (incluso como consecuencia de la satisfacción de otras dependencias de bibliotecas cargadas dinámicamente).

Hasta ahora solo he hablado sobre el código de la biblioteca. En este punto, todo lo que queda son asignaciones hechas por la propia aplicación o en nombre de la aplicación por las bibliotecas.Mi punto de vista, y voy a admitir que no es ortodoxo, es que la liberación de tales objetos no es solo innecesaria sino dañina. La razón principal por la que digo esto es porque la mayoría de las aplicaciones de larga duración han acumulado bastante memoria asignada que no están utilizando de manera significativa (piense en el buffer de deshacer en un procesador de texto o en el historial en un navegador). En un sistema con carga moderada, gran parte de esta información se ha cambiado al disco cuando termina la aplicación. Si desea liberarla, vas a terminar caminar por toda las direcciones de memoria de salida intercambiadas rastrear todos los punteros a liberar,

  • poner desgaste inútil en los componentes físicos del disco duro
  • haciendo la espera del usuario de su aplicación para salir
  • causando datos de otras aplicaciones todavía en uso para obtener intercambiado, por lo que corren más lento

Todo esto en el nombre de una ridícula "debe liberar todo lo que asignas "regla".

Para aplicaciones de vida corta, no es tanto una gran cosa, pero a menudo puede simplificar la implementación de aplicaciones de corta duración que realizan una única tarea lineal y salir si no se molesta en liberar toda la memoria que tienen asignar. Piensa en la mayoría de las utilidades de línea de comandos de Unix. ¿Hay algún uso para escribir los bucles para sed para liberar todas sus expresiones regulares compiladas antes de salir? ¿No podría el tiempo de los programadores gastarse en algo más productivo?

Cuestiones relacionadas