c++ c memory-leaks

c++ - ¿Las fugas de memoria están bien?



memory-leaks (30)

¿Es aceptable tener una pérdida de memoria en su aplicación C o C ++?

¿Qué sucede si asigna algo de memoria y la usa hasta la última línea de código en su aplicación (por ejemplo, el destructor de un objeto global)? Siempre que el consumo de memoria no crezca con el tiempo, ¿está bien confiar en que el sistema operativo libere su memoria cuando finalice su aplicación (en Windows, Mac y Linux)? ¿Consideraría esto como una pérdida de memoria real si la memoria se usara continuamente hasta que el sistema operativo la liberara?

¿Qué pasaría si una biblioteca de terceros te forzara esta situación? ¿Se negaría a usar esa biblioteca de terceros sin importar cuán grande pueda ser?

Solo veo una desventaja práctica, y es que estas fugas benignas se mostrarán con herramientas de detección de fugas de memoria como falsos positivos.


Creo que en tu situación la respuesta puede ser que está bien. Pero definitivamente necesitas documentar que la pérdida de memoria es una decisión consciente. No quiere que venga un programador de mantenimiento, abofetee su código dentro de una función y llámelo un millón de veces. Entonces, si toma la decisión de que una fuga está bien, debe documentarla (EN GRANDES CARTAS) para quien tenga que trabajar en el programa en el futuro.

Si se trata de una biblioteca de terceros, puede quedar atrapado. Pero definitivamente documente que se produce esta fuga.

Pero básicamente, si la pérdida de memoria es una cantidad conocida, como un búfer de 512 KB o algo así, entonces no es un problema. Si la pérdida de memoria sigue creciendo como cada vez que llama a una biblioteca, su memoria aumenta en 512 KB y no se libera, entonces puede tener un problema. Si lo documenta y controla la cantidad de veces que se ejecuta la llamada, puede ser manejable. Pero entonces realmente necesita documentación porque mientras 512 no es mucho, 512 más de un millón de llamadas es mucho.

También necesitas revisar la documentación de tu sistema operativo. Si se trata de un dispositivo integrado, puede haber sistemas operativos que no liberen toda la memoria de un programa que sale. No estoy seguro, tal vez esto no es cierto. Pero vale la pena mirar.


Creo que la respuesta es no, nunca permitir una pérdida de memoria, y tengo algunas razones que no he visto explícitamente. Aquí hay excelentes respuestas técnicas, pero creo que la respuesta real depende de más razones sociales / humanas.

(En primer lugar, tenga en cuenta que, como han mencionado otros, una verdadera fuga es cuando su programa, en cualquier momento, pierde el seguimiento de los recursos de memoria que ha asignado. En C, esto sucede cuando se malloc() a un puntero y se deja que el puntero salga del alcance sin hacer un free() primero.)

El quid importante de su decisión aquí es el hábito. Cuando codificas en un lenguaje que usa punteros, vas a usar mucho los punteros. Y los punteros son peligrosos; Son la forma más fácil de agregar todo tipo de problemas graves a su código.

Cuando estás programando, a veces vas a estar concentrado y otras veces estás cansado o enojado o preocupado. Durante esos momentos un tanto distraídos, estás codificando más en el piloto automático. El efecto del piloto automático no distingue entre un código único y un módulo en un proyecto más grande. Durante esos momentos, los hábitos que establezca serán los que terminarán en su base de código.

Así que no, nunca permita fugas de memoria por la misma razón por la que aún debe revisar sus puntos ciegos al cambiar de carril, incluso si es el único automóvil en la carretera en este momento. Durante los momentos en que su cerebro activo está distraído, los buenos hábitos son todo lo que puede salvarlo de errores desastrosos.

Más allá del problema del "hábito", los indicadores son complejos y, a menudo, requieren una gran cantidad de capacidad mental para realizar un seguimiento mental. Es mejor no "enturbiar el agua" cuando se trata de usar punteros, especialmente cuando eres nuevo en la programación.

También hay un aspecto más social. Con el uso adecuado de malloc() y free() , cualquier persona que mire su código estará a gusto; usted está administrando sus recursos. Sin embargo, si no lo hace, inmediatamente sospecharán un problema.

Tal vez haya averiguado que la pérdida de memoria no daña nada en este contexto, pero cada mantenedor de su código tendrá que resolverlo también en su cabeza cuando lea ese fragmento de código. Al utilizar free() , elimina la necesidad de considerar el problema.

Finalmente, la programación es escribir un modelo mental de un proceso a un lenguaje no ambiguo para que una persona y una computadora puedan entender perfectamente dicho proceso. Una parte vital de la buena práctica de programación nunca es introducir una ambigüedad innecesaria.

La programación inteligente es flexible y genérica. La mala programación es ambigua.


Daré la respuesta impopular pero práctica de que siempre es incorrecto liberar memoria a menos que hacerlo reduzca el uso de memoria de su programa . Por ejemplo, un programa que realiza una sola asignación o una serie de asignaciones para cargar el conjunto de datos que utilizará durante toda su vida útil no tiene necesidad de liberar nada. En el caso más común de un programa grande con requisitos de memoria muy dinámicos (piense en un navegador web), obviamente debería liberar memoria que ya no está usando tan pronto como sea posible (por ejemplo, cerrar una pestaña / documento / etc). , pero no hay razón para liberar nada cuando el usuario selecciona "salir", y hacerlo es perjudicial para la experiencia del usuario.

¿Por qué? Liberar la memoria requiere tocar la memoria. Incluso si la implementación de malloc de su sistema no almacena metadatos adyacentes a los bloques de memoria asignados, es probable que vaya a recorrer estructuras recursivas solo para encontrar todos los punteros que necesita liberar.

Ahora, supongamos que su programa ha funcionado con un gran volumen de datos, pero que no ha tocado la mayoría durante un tiempo (nuevamente, el navegador web es un gran ejemplo). Si el usuario está ejecutando una gran cantidad de aplicaciones, es probable que una buena parte de esos datos se hayan intercambiado en el disco. Si acaba de salir (0) o volver de la principal, se cierra instantáneamente. Gran experiencia de usuario. Si te tomas la molestia de intentar liberar todo, puedes pasar 5 segundos o más intercambiando todos los datos, solo para desecharlos inmediatamente después de eso. Desperdicio del tiempo del usuario. Desperdicio de la duración de la batería del portátil. Desperdicio de desgaste en el disco duro.

Esto no es sólo teórico. Cada vez que me encuentro con demasiadas aplicaciones cargadas y el disco comienza a golpear, ni siquiera considero hacer clic en "salir". Llego a una terminal lo más rápido que puedo y escribo killall -9 ... porque sé que "exit" solo empeorará las cosas.


En este tipo de pregunta, el contexto lo es todo. Personalmente, no soporto las fugas, y en mi código hago todo lo posible para solucionarlas si surgen, pero no siempre vale la pena reparar una fuga, y cuando la gente me paga por la hora que tengo, en ocasiones les dije que no valía la pena pagar una fuga en su código. Dejame darte un ejemplo:

Estaba evaluando un proyecto, haciendo un trabajo de perfección y arreglando muchos errores. Hubo una fuga durante la inicialización de las aplicaciones que rastreé y entendí completamente. Repararlo correctamente habría requerido un día más o menos refactorizar una parte del código funcional. Podría haber hecho algo intrépido (como rellenar el valor en un global y captarlo en algún punto que sé que ya no se usaba para liberarlo), pero eso solo habría causado más confusión en el siguiente tipo que tuvo que tocar el código.

Personalmente, no habría escrito el código de esa manera en primer lugar, pero la mayoría de nosotros no siempre trabajamos en bases de código prístinas y bien diseñadas, y algunas veces hay que mirar estas cosas de manera pragmática. La cantidad de tiempo que me hubiera costado arreglar esa fuga de 150 bytes se podría dedicar a realizar mejoras algorítmicas que recortaron megabytes de RAM.

En última instancia, decidí que no valía la pena repararlo con una fuga de 150 bytes para una aplicación que se usaba en torno a un concierto de ram y que funcionaba en una máquina dedicada, por lo que escribí un comentario que decía que se había filtrado, qué había que cambiar para corregirlo. Eso, y por qué no valía la pena en ese momento.


En teoría no, en la práctica depende .

Realmente depende de cuántos datos está trabajando el programa, con qué frecuencia se ejecuta el programa y si se está ejecutando o no constantemente.

Si tengo un programa rápido que lee una pequeña cantidad de datos hace un cálculo y sale, nunca se notará una pequeña pérdida de memoria. Debido a que el programa no se ejecuta durante mucho tiempo y solo utiliza una pequeña cantidad de memoria, la fuga será pequeña y se liberará cuando exista el programa.

Por otro lado, si tengo un programa que procesa millones de registros y se ejecuta durante mucho tiempo, una pequeña pérdida de memoria puede hacer que la máquina pierda el tiempo suficiente.

En cuanto a las bibliotecas de terceros que tienen fugas, si causan un problema, corrija la biblioteca o encuentre una mejor alternativa. Si no causa un problema, ¿realmente importa?


Estoy seguro de que alguien puede encontrar una razón para decir que sí, pero no seré yo. En lugar de decir no, voy a decir que esto no debería ser una pregunta de sí / no. Hay formas de administrar o contener las pérdidas de memoria, y muchos sistemas las tienen.

Hay sistemas de la NASA en los dispositivos que salen de la tierra que planean esto. Los sistemas se reiniciarán automáticamente cada cierto tiempo para que las fugas de memoria no sean fatales para la operación en general. Solo un ejemplo de contención.


Incluso si está seguro de que su pérdida de memoria ''conocida'' no causará estragos, no lo haga. En el mejor de los casos, allanará el camino para que cometa un error similar y probablemente más crítico en un momento y lugar diferente.

Para mí, preguntar esto es como preguntar "¿Puedo romper la luz roja a las 3 AM de la mañana cuando no hay nadie cerca?". Bien seguro, puede que no cause ningún problema en ese momento, pero proporcionará una palanca para que hagas lo mismo en hora punta.


Me sorprende ver tantas definiciones incorrectas de lo que realmente es una pérdida de memoria. Sin una definición concreta, una discusión sobre si es algo malo o no irá a ninguna parte.

Como algunos comentaristas han señalado correctamente, una pérdida de memoria solo ocurre cuando la memoria asignada por un proceso queda fuera del alcance en la medida en que el proceso ya no puede hacer referencia o eliminarla.

Un proceso que agarra más y más memoria no necesariamente tiene fugas. Mientras sea capaz de hacer referencia y desasignar esa memoria, permanecerá bajo el control explícito del proceso y no se habrá filtrado. El proceso puede estar mal diseñado, especialmente en el contexto de un sistema donde la memoria es limitada, pero esto no es lo mismo que una fuga. A la inversa, perder el alcance de, digamos, un búfer de 32 bytes sigue siendo una fuga, aunque la cantidad de memoria perdida es pequeña. Si cree que esto es insignificante, espere hasta que alguien ajuste un algoritmo alrededor de su biblioteca y lo llame 10,000 veces.

No veo ninguna razón para permitir fugas en su propio código, por pequeño que sea. Los lenguajes de programación modernos, como C y C ++, hacen todo lo posible para ayudar a los programadores a prevenir tales fugas y rara vez existe un buen argumento para no adoptar buenas técnicas de programación, especialmente cuando se combinan con instalaciones de lenguaje específicas, para evitar fugas.

En lo que respecta al código existente o de terceros, donde su control sobre la calidad o la capacidad para realizar un cambio puede ser muy limitado, dependiendo de la gravedad de la fuga, puede verse obligado a aceptar o tomar medidas de mitigación, como reiniciar el proceso regularmente para reducir El efecto de la fuga.

Es posible que no sea posible cambiar o reemplazar el código existente (con fugas) y, por lo tanto, es posible que esté obligado a aceptarlo. Sin embargo, esto no es lo mismo que declarar que está bien.


Muchas personas parecen tener la impresión de que una vez que se libera la memoria, se devuelve instantáneamente al sistema operativo y puede ser utilizada por otros programas.

Esto no es cierto Los sistemas operativos comúnmente administran la memoria en páginas de 4KiB. malloc y otros tipos de gestión de memoria obtienen páginas del sistema operativo y las administran de la forma que consideren adecuada. Es muy probable que free() no devuelva las páginas al sistema operativo, bajo el supuesto de que su programa maltratará más memoria más adelante.

No estoy diciendo que free() nunca devuelva la memoria al sistema operativo. Puede suceder, especialmente si está liberando grandes cantidades de memoria. Pero no hay garantía.

El hecho importante: si no libera memoria que ya no necesita, más mallocs está garantizado para consumir aún más memoria. Pero si liberas primero, malloc podría reutilizar la memoria liberada.

¿Qué significa esto en la práctica? Esto significa que si sabe que su programa no va a requerir más memoria de ahora en adelante (por ejemplo, está en la fase de limpieza), liberar memoria no es tan importante. Sin embargo, si el programa puede asignar más memoria más adelante, debe evitar las fugas de memoria, especialmente las que pueden ocurrir repetidamente.

También vea este comentario para obtener más detalles sobre por qué la liberación de memoria justo antes de la terminación es mala.

Un comentarista no pareció entender que llamar a free() no permite automáticamente que otros programas utilicen la memoria liberada. ¡Pero ese es el punto entero de esta respuesta!

Entonces, para convencer a la gente, demostraré un ejemplo donde free () hace muy poco bien. Para que las matemáticas sean fáciles de seguir, pretenderé que el sistema operativo administra la memoria en páginas de 4000 bytes.

Supongamos que asigna diez mil bloques de 100 bytes (por simplicidad, ignoraré la memoria adicional que se necesitaría para administrar estas asignaciones). Esto consume 1MB, o 250 páginas. Si luego liberas 9000 de estos bloques al azar, te quedan solo 1000 bloques, pero están dispersos por todo el lugar. Estadísticamente, alrededor de 5 de las páginas estarán vacías. Los otros 245 tendrán cada uno al menos un bloque asignado en ellos. Eso equivale a 980KB de memoria, que el sistema operativo no puede reclamar, ¡aunque ahora solo tiene 100KB asignados!

Por otro lado, ahora puede malloc () 9000 bloques más sin aumentar la cantidad de memoria que está atando su programa.

Incluso cuando free() técnicamente podría devolver la memoria al sistema operativo, puede que no lo haga. free() necesita lograr un equilibrio entre el funcionamiento rápido y el ahorro de memoria. Y además, un programa que ya ha asignado una gran cantidad de memoria y luego la ha liberado es probable que vuelva a hacerlo. Un servidor web debe manejar la solicitud tras solicitud tras solicitud - tiene sentido mantener un poco de memoria disponible para que no tenga que pedir memoria al sistema operativo todo el tiempo.


No considero que sea una pérdida de memoria a menos que la cantidad de memoria que se está "utilizando" siga creciendo. Tener un poco de memoria inédita, aunque no es ideal, no es un gran problema a menos que la cantidad de memoria requerida siga creciendo.


No hay nada conceptualmente incorrecto en tener que limpiar el sistema operativo después de ejecutar la aplicación.

Realmente depende de la aplicación y de cómo se ejecutará. Las fugas que ocurren continuamente en una aplicación que debe ejecutarse durante semanas deben ser atendidas, pero una pequeña herramienta que calcula un resultado sin una necesidad de memoria demasiado alta no debería ser un problema.

Existe una razón por la que muchos lenguajes de scripting no recolectan las referencias cíclicas ... para sus patrones de uso, no es un problema real y, por lo tanto, sería un desperdicio de recursos tan grande como la memoria desperdiciada.


No.

Como profesionales, la pregunta que no deberíamos hacernos es: "¿Está bien hacer esto?" sino más bien "¿Hay alguna razón para hacer esto?" Y "cazar esa pérdida de memoria es un dolor" no es una buena razón.

Me gusta mantener las cosas simples. Y la regla simple es que mi programa no debe tener pérdidas de memoria.

Eso hace que mi vida sea simple, también. Si detecto una pérdida de memoria, la elimino, en lugar de ejecutar una estructura de árbol de decisiones elaborada para determinar si es una pérdida de memoria "aceptable".

Es similar a las advertencias del compilador: ¿la advertencia será fatal para mi aplicación en particular? Tal vez no.

Pero en última instancia es una cuestión de disciplina profesional. Tolerar las advertencias del compilador y tolerar las fugas de memoria es un mal hábito que finalmente me morderá la parte trasera.

Para llevar las cosas al extremo, ¿sería aceptable para un cirujano dejar algún equipo de operación dentro de un paciente?

Aunque es posible que surja una circunstancia en la que el costo / riesgo de remover esa pieza del equipo exceda el costo / riesgo de dejarlo, y podría haber circunstancias en las que fue inofensivo, si veo esta pregunta publicada en SurgeonOverflow.com y vio cualquier respuesta que no fuera "no", minaría seriamente mi confianza en la profesión médica.

-

Si una biblioteca de un tercero me forzara esta situación, me llevaría a sospechar seriamente la calidad general de la biblioteca en cuestión. Sería como si probara un automóvil y encontrase un par de arandelas sueltas y tuercas en uno de los portavasos; puede que no sea un gran problema en sí mismo, pero presenta una falta de compromiso con la calidad, por lo que consideraría alternativas.


Primero debe darse cuenta de que hay una gran diferencia entre una pérdida de memoria percibida y una pérdida de memoria real. Con mucha frecuencia, las herramientas de análisis informarán sobre muchas pistas falsas y etiquetarán algo como que se ha filtrado (memoria o recursos como identificadores, etc.) donde en realidad no lo está. Muchas veces esto se debe a la arquitectura de la herramienta de análisis. Por ejemplo, ciertas herramientas de análisis informarán los objetos de tiempo de ejecución como pérdidas de memoria porque nunca ve los objetos liberados. Pero la desasignación se produce en el código de cierre del tiempo de ejecución, que la herramienta de análisis podría no ver.

Dicho esto, todavía habrá ocasiones en las que tendrá pérdidas de memoria reales que son muy difíciles de encontrar o muy difíciles de solucionar. Así que ahora la pregunta es: ¿está bien dejarlos en el código?

La respuesta ideal es, "no, nunca". Una respuesta más pragmática puede ser "no, casi nunca". Muy a menudo en la vida real tiene un número limitado de recursos y tiempo para resolver y una lista interminable de tareas. Cuando una de las tareas es eliminar las pérdidas de memoria, la ley de los rendimientos decrecientes muy a menudo entra en juego. Podría eliminar, por ejemplo, el 98% de todas las fugas de memoria en una aplicación en una semana, pero el 2% restante podría llevar meses. En algunos casos, incluso podría ser imposible eliminar ciertas fugas debido a la arquitectura de la aplicación sin una refactorización importante del código. Tienes que sopesar los costos y beneficios de eliminar el 2% restante.


Puedo contar con una mano el número de fugas "benignas" que he visto a lo largo del tiempo.

Así que la respuesta es un sí muy calificado.

Un ejemplo. Si tiene un recurso singleton que necesita un búfer para almacenar una cola circular o deque, pero no sabe qué tan grande debe ser el búfer y no puede pagar la sobrecarga de bloqueo o de cada lector, luego asigne un búfer de duplicación exponencial, pero no liberar los antiguos perderá una cantidad limitada de memoria por cola / deque. El beneficio para estos es que aceleran cada acceso dramáticamente y pueden cambiar la asintótica de las soluciones multiprocesador al no arriesgarse a disputar un bloqueo.

He visto que este enfoque es muy beneficioso para las cosas con recuentos muy claros, como los deques de robo de trabajo por CPU, y en mucho menor grado en el búfer utilizado para mantener el estado singleton /proc/self/maps en Hans El recolector de basura conservador de Boehm para C / C ++, que se utiliza para detectar los conjuntos de raíces, etc.

Si bien técnicamente es una fuga, ambos casos están limitados en tamaño y en el caso de deque de robo de trabajo circular que se puede cultivar, hay una gran ganancia de rendimiento a cambio de un factor acotado de 2 en el uso de memoria para las colas.


Si asigna memoria y la usa hasta la última línea de su programa, eso no es una fuga. Si asigna memoria y se olvida de ella, incluso si la cantidad de memoria no aumenta, eso es un problema. La memoria asignada pero no utilizada puede hacer que otros programas se ejecuten más lentamente o no funcionen.


Si asigna un montón de almacenamiento dinámico al principio de su programa, y ​​no lo libera al salir, eso no es una pérdida de memoria per se. Una pérdida de memoria es cuando su programa recorre una sección del código, y ese código asigna un montón y luego "pierde el rastro" de él sin liberarlo.

De hecho, no es necesario realizar llamadas a free () o eliminar justo antes de salir. Cuando el proceso finaliza, toda su memoria es reclamada por el sistema operativo (este es ciertamente el caso con POSIX. En otros sistemas operativos, especialmente los integrados, YMMV).

La única precaución que tengo al no liberar la memoria en el momento de la salida es que si alguna vez refactoriza su programa para que, por ejemplo, se convierta en un servicio que espere la entrada, haga lo que sea que haga su programa, luego haga un bucle para esperar Otra llamada de servicio, entonces lo que ha codificado puede convertirse en una pérdida de memoria.


Si bien la mayoría de las respuestas se concentran en las pérdidas de memoria reales (que no están bien nunca, porque son un signo de codificación descuidada), esta parte de la pregunta me parece más interesante:

¿Qué sucede si asigna algo de memoria y la usa hasta la última línea de código en su aplicación (por ejemplo, el deconstructor de un objeto global)? Siempre que el consumo de memoria no crezca con el tiempo, ¿está bien confiar en que el sistema operativo libere su memoria cuando finalice su aplicación (en Windows, Mac y Linux)? ¿Consideraría esto como una pérdida de memoria real si la memoria se usara continuamente hasta que el sistema operativo la liberara?

Si se utiliza la memoria asociada, no puede liberarla antes de que finalice el programa. Si el libre es hecho por la salida del programa o por el sistema operativo no importa. Mientras esto esté documentado, para que el cambio no introduzca pérdidas de memoria reales, y siempre que no haya un destructor de C ++ o una función de limpieza de C involucrada en la imagen. Un archivo no cerrado puede revelarse a través de un objeto FILE filtrado, pero un fclose () faltante también puede hacer que el búfer no se vacíe.

Así que, volviendo al caso original, en mi humilde opinión está perfectamente bien en sí mismo, tanto que Valgrind, uno de los detectores de fugas más potentes, tratará dichas fugas solo si se solicita. En Valgrind, cuando sobrescribes un puntero sin liberarlo de antemano, se considera una pérdida de memoria, ya que es más probable que vuelva a ocurrir y que el montón aumente infinitamente.

Entonces, no hay nfreed bloques de memoria que todavía son accesibles. Uno podría asegurarse de liberarlos a todos a la salida, pero eso es solo una pérdida de tiempo en sí mismo. El punto es si podrían ser liberados antes . Reducir el consumo de memoria es útil en cualquier caso.


esto es tan específico del dominio que apenas vale la pena responder. Usa tu maldita cabeza.

  • sistema operativo del transbordador espacial: no, no se permiten fugas de memoria
  • Código de prueba de concepto de desarrollo rápido: reparar todas esas fugas de memoria es una pérdida de tiempo.

Y hay un espectro de situaciones intermedias.

El costo de oportunidad ($$$) de demorar el lanzamiento de un producto para reparar todas las pérdidas de memoria, excepto las peores, es usualmente menoscabando cualquier sensación de ser "descuidado o poco profesional". Tu jefe te paga para que le hagas dinero, no para tener sentimientos cálidos y confusos.


Como regla general, si tiene pérdidas de memoria que cree que no puede evitar, entonces debe pensar más en la propiedad de los objetos.

Pero a su pregunta, mi respuesta en pocas palabras es En código de producción, sí. Durante el desarrollo, no . Esto puede parecer al revés, pero aquí está mi razonamiento:

En la situación que describe, donde se guarda la memoria hasta el final del programa, es perfectamente correcto no liberarla. Una vez que el proceso finalice, el sistema operativo se limpiará de todos modos. De hecho, podría mejorar la experiencia del usuario: en un juego en el que he trabajado, los programadores pensaron que sería más limpio liberar toda la memoria antes de salir, ¡lo que provocó que el cierre del programa demorara hasta medio minuto! Un cambio rápido que acaba de llamar exit () hizo que el proceso desapareciera de inmediato y devolvió al usuario al escritorio donde quería estar.

Sin embargo, tiene razón con respecto a las herramientas de depuración: darán un ataque, y todos los falsos positivos podrían hacer que encontrar su verdadera memoria sea un dolor. Y debido a eso, siempre escriba el código de depuración que libera la memoria y deshabilítelo cuando realice el envío.


Consigamos nuestras definiciones correctas, primero. Una pérdida de memoria es cuando la memoria se asigna dinámicamente, por ejemplo, con malloc() , y todas las referencias a la memoria se pierden sin la correspondiente libertad. Una forma fácil de hacer uno es así:

#define BLK ((size_t)1024) while(1){ void * vp = malloc(BLK); }

Tenga en cuenta que cada vez que se recurre al bucle while (1), se asignan 1024 (+ sobrecarga) bytes, y la nueva dirección se asigna a vp; no hay puntero restante a los bloques malloc''ed anteriores. Se garantiza que este programa se ejecutará hasta que se agote el montón, y no hay forma de recuperar nada de la memoria de malloc''ed. La memoria se está "escapando" del montón, para no ser vista nunca más.

Sin embargo, lo que estás describiendo suena como

int main(){ void * vp = malloc(LOTS); // Go do something useful return 0; }

Usted asigna la memoria, trabaje con ella hasta que el programa termine. Esto no es una pérdida de memoria; no daña el programa y toda la memoria se eliminará automáticamente cuando el programa termine.

En general, debe evitar las fugas de memoria. Primero, porque al igual que la altitud por encima de ti y el combustible en el hangar, la memoria que se filtró y no se puede recuperar es inútil; En segundo lugar, es mucho más fácil codificar correctamente, sin perder memoria, al principio que encontrar una pérdida de memoria más tarde.


Creo que está bien si está escribiendo un programa destinado a perder memoria (es decir, para probar el impacto de las pérdidas de memoria en el rendimiento del sistema).


Generalmente, una pérdida de memoria en una aplicación independiente no es fatal, ya que se limpia cuando el programa sale.

¿Qué hace usted para los programas del servidor que están diseñados para que no salgan?

Si usted es el tipo de programador que no diseña e implementa el código donde los recursos se asignan y liberan correctamente, entonces no quiero tener nada que ver con usted o su código. Si no te importa limpiar tu memoria filtrada, ¿qué hay de tus cerraduras? ¿Los dejas colgando por ahí también? ¿Dejas pequeños montones de archivos temporales en varios directorios?

¿Perder esa memoria y dejar que el programa la limpie? No absolutamente no. Es un mal hábito, que conduce a errores, errores y más errores.

Limpiar después de ti mismo Yo mamá ya no trabaja aquí.


Voy a responder que no.

En teoría, el sistema operativo se limpiará después de usted si deja un desastre (ahora eso es simplemente grosero, pero dado que las computadoras no tienen sentimientos, podría ser aceptable). Pero no puede anticipar cada situación posible que pueda ocurrir cuando se ejecuta su programa. Por lo tanto (a menos que sea capaz de realizar una prueba formal de algún comportamiento), crear pérdidas de memoria es simplemente irresponsable y descuidado desde un punto de vista profesional.

Si un componente de un tercero pierde memoria, este es un argumento muy fuerte en contra del uso, no solo por el efecto inminente sino también porque muestra que los programadores trabajan de manera descuidada y que esto también podría afectar otras métricas. Ahora, cuando se consideran los sistemas heredados, esto es difícil (considere los componentes de navegación web: que yo sepa, todos pierden memoria) pero debería ser la norma.


Creo que has respondido tu propia pregunta. El mayor inconveniente es cómo interfieren con las herramientas de detección de fugas de memoria, pero creo que el inconveniente es un ENORME inconveniente para ciertos tipos de aplicaciones.

Trabajo con aplicaciones de servidor heredadas que se supone que son sólidas pero tienen fugas y las globales se interponen en el camino de las herramientas de detección de memoria. Tiene mucha importancia.

En el libro "Colapso" de Jared Diamond, el autor se pregunta qué pensaba el tipo que cortó el último árbol en la Isla de Pascua, el árbol que habría necesitado para construir una canoa para salir de la isla. Me pregunto sobre el día en que hace muchos años se agregó nuestro primer código global a nuestro código base. Ese fue el día en que debería haber sido atrapado.


Esto ya fue discutido ad nauseam . La conclusión es que una pérdida de memoria es un error y debe solucionarse. Si una biblioteca de terceros pierde memoria, eso hace que uno se pregunte qué más hay de malo, ¿no? Si estuviera construyendo un automóvil, ¿usaría un motor que ocasionalmente gotea aceite? Después de todo, alguien más hizo el motor, así que no es tu culpa y no puedes arreglarlo, ¿verdad?


Estoy de acuerdo con vfilby - depende En Windows, tratamos las fugas de memoria como errores relativamente serios. Pero, depende mucho del componente.

Por ejemplo, las fugas de memoria no son muy graves para los componentes que se ejecutan con poca frecuencia y por períodos de tiempo limitados. Estos componentes se ejecutan, hacen su trabajo, luego salen. Cuando salen todos sus recuerdos se liberan implícitamente.

Sin embargo, las fugas de memoria en los servicios u otros componentes de ejecución prolongada (como el shell) son muy graves. La razón es que estos errores "roban" la memoria con el tiempo. La única forma de recuperar esto es reiniciar los componentes. La mayoría de las personas no saben cómo reiniciar un servicio o el shell, por lo que si el rendimiento de su sistema se resiente, solo se reinicia.

Entonces, si tiene una fuga, evalúe su impacto de dos maneras

  1. Para su software y la experiencia de su usuario.
  2. Al sistema (y al usuario) en términos de ser frugales con los recursos del sistema.
  3. Impacto de la corrección en el mantenimiento y la fiabilidad.
  4. Probabilidad de causar una regresión en otro lugar.

Foredecker


Históricamente, sí importaba en algunos sistemas operativos en algunos casos de borde. Estos casos extremos podrían existir en el futuro.

Aquí hay un ejemplo, en SunOS en la era Sun 3, hubo un problema si un proceso usaba exec (o más tradicionalmente fork y luego exec), el nuevo proceso subsiguiente heredaría la misma huella de memoria que el padre y no podría reducirse. . Si un proceso principal asignó 1/2 gigabyte de memoria y no la liberó antes de llamar a exec, el proceso secundario comenzaría a usar esa misma 1/2 gigatividad (aunque no estuviera asignada). Este comportamiento fue mejor exhibido por SunTools (su sistema de ventanas por defecto), que era un montón de memoria. Cada aplicación que generó fue creada a través de fork / exec y la huella heredada de SunTools, llenando rápidamente el espacio de intercambio.


No, no debería haber fugas que el sistema operativo limpie para usted. La razón (no mencionada en las respuestas anteriores hasta donde pude verificar) es que nunca se sabe cuándo se volverá a usar su main () como función / módulo en otro programa . Si su main () se convierte en una función llamada con frecuencia en el software de otra persona, este software tendrá una pérdida de memoria que se come la memoria con el tiempo.

KIV


Realmente no es una fuga si es intencional y no es un problema a menos que sea una cantidad significativa de memoria, o podría llegar a ser una cantidad significativa de memoria. Es bastante común no limpiar las asignaciones globales durante la vida útil de un programa. Si la fuga está en un servidor o una aplicación de larga duración, crece con el tiempo, entonces es un problema.


Veo el mismo problema que todas las preguntas de escenarios como esta: ¿Qué sucede cuando cambia el programa y, de repente, esa pequeña pérdida de memoria se llama diez millones de veces y el final de su programa se encuentra en un lugar diferente, por lo que importa? Si está en una biblioteca, registre un error con los mantenedores de la biblioteca, no ponga una fuga en su propio código.