[C++] ¿Las pérdidas de memoria alguna vez están bien?



Answers

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

Question

¿Alguna vez 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)? Mientras el consumo de memoria no crezca con el tiempo, ¿está bien confiar en que el sistema operativo liberará la memoria cuando termine la aplicación (en Windows, Mac y Linux)? ¿Consideraría esto una fuga de memoria real si la memoria se usara continuamente hasta que el sistema operativo la liberara?

¿Qué pasa si una biblioteca de terceros te obliga a esta situación? ¿Rehusaría usar esa biblioteca de terceros sin importar cuán grande podría ser?

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




Incluso si está seguro de que su fuga de memoria "conocida" no causará estragos, no lo haga. En el mejor de los casos, allanará el camino para que usted cometa un error similar y probablemente más crítico en un lugar y hora 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 claro, puede que no cause ningún problema en ese momento, pero proporcionará una palanca para que hagas lo mismo en hora punta!




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

Estaba trabajando en un proyecto, realizando un trabajo de perfilación y solucionando muchos errores. Hubo una fuga durante la inicialización de las aplicaciones que rastreé y entendí completamente. Arreglarlo correctamente hubiera requerido un día o más para refactorizar una parte del código funcional. Pude haber hecho algo raro (como meter el valor en un global y agarrarlo en algún momento, sé que ya no estaba en uso para liberarlo), pero eso habría causado más confusión al siguiente tipo que tuvo que tocar el código.

Personalmente, no hubiera escrito el código de esa manera, en primer lugar, pero la mayoría de nosotros no siempre trabajamos en bases de datos bien diseñadas y prístinas, y en ocasiones hay que mirar estas cosas pragmáticamente. La cantidad de tiempo que me hubiera llevado corregir esa fuga de 150 bytes podría, en cambio, ser usada para hacer mejoras algorítmicas que afeitaran los megabytes de RAM.

Finalmente, decidí que filtrar 150 bytes para una aplicación que se usaba alrededor de un gig de ram y que funcionaba en una máquina dedicada no valía la pena, así que escribí un comentario diciendo que se había filtrado, que era necesario cambiar para corregir y por qué no valió la pena en ese momento.




No, you should not have leaks that the OS will clean for you. The reason (not mentioned in the answers above as far as I could check) is that you never know when your main() will be re-used as a function/module in another program . If your main() gets to be a frequently-called function in another persons' software - this software will have a memory leak that eats memory over time.

KIV




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




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

Realmente depende de la cantidad de datos en los que el programa está trabajando, de la frecuencia con la que se ejecuta el programa y de si se ejecuta constantemente.

Si tengo un programa rápido que dice que 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 por mucho tiempo y solo utiliza una pequeña cantidad de memoria, la fuga será pequeña y se liberará cuando el programa exista.

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

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




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 pérdidas de memoria
  • código de prueba de concepto de desarrollo rápido: arreglar todas esas pérdidas de memoria es una pérdida de tiempo.

y hay un espectro de situaciones intermedias.

el costo de oportunidad ($$$) de retrasar la publicación de un producto para reparar todo, pero las peores pérdidas de memoria suelen empequeñecer cualquier sensación de "descuidado o poco profesional". Su jefe le paga para hacerle ganar dinero, no para tener sentimientos cálidos y confusos.




Voy a dar la respuesta impopular pero práctica de que siempre está mal liberar memoria a menos que hacerlo reduzca el uso de memoria de su programa . Por ejemplo, un programa que realiza una única asignación o serie de asignaciones para cargar el conjunto de datos que utilizará durante toda su vida útil, no necesita 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), debería liberar memoria que ya no usa tan pronto como pueda (por ejemplo, cerrar una pestaña / documento / etc.). , pero no hay razón para liberar nada cuando el usuario selecciona los clics "salir", y hacerlo realmente es perjudicial para la experiencia del usuario.

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

Ahora, supongamos que su programa ha trabajado con un gran volumen de datos, pero que no ha tocado la mayor parte del mismo por un tiempo (de nuevo, el navegador web es un gran ejemplo). Si el usuario ejecuta muchas aplicaciones, es probable que una buena parte de esos datos se haya intercambiado en el disco. Si acaba de salir (0) o regresar de main, sale al instante. Gran experiencia de usuario. Si se toma la molestia de intentar liberar todo, puede pasar 5 segundos o más intercambiando todos los datos, solo para tirarlos inmediatamente después de eso. Pérdida de tiempo del usuario. Pérdida de la vida de la batería de la computadora portátil. Desperdicio de desgaste en el disco duro.

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




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

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




Puedo contar con una mano la cantidad de fugas "benignas" que he visto a lo largo del tiempo.

Entonces 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 permitirse la sobrecarga de bloqueo o cada lector, entonces asigna un búfer que se duplica exponencialmente pero si no se liberan, las antiguas perderán una cantidad limitada de memoria por cola / deque. El beneficio para estos es que aceleran cada acceso de forma espectacular y pueden cambiar las asintéticas de las soluciones multiprocesador al no arriesgarse nunca a tener un bloqueo.

He visto este enfoque utilizado para obtener un gran beneficio para cosas con recuentos muy claramente fijados, como los deques por robo de trabajo por CPU, y en un grado mucho menor en el buffer utilizado para mantener el estado singleton /proc/self/maps en Hans El recolector de basura conservador de Boehm para C / C ++, que se usa para detectar los conjuntos de raíz, etc.

Aunque técnicamente es una fuga, ambos casos tienen un tamaño limitado y en el caso de robo de robo de trabajo circulable crece una gran ganancia de rendimiento a cambio de un factor de incremento acotado de 2 en el uso de memoria para las colas.




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

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

Hay una razón por la cual muchos lenguajes de scripting no recogen referencias cíclicas ... por sus patrones de uso, no es un problema real y sería un desperdicio de recursos como la memoria desperdiciada.




Generally a memory leak in a stand alone application is not fatal, as it gets cleaned up when the program exits.

What do you do for Server programs that are designed so they don't exit?

If you are the kind of programmer that does not design and implement code where the resources are allocated and released correctly, then I don't want anything to do with you or your code. If you don't care to clean up your leaked memory, what about your locks? Do you leave them hanging out there too? Do you leave little turds of temporary files laying around in various directories?

Leak that memory and let the program clean it up? No. Absolutely not. It's a bad habit, that leads to bugs, bugs, and more bugs.

Clean up after yourself. Yo momma don't work here no more.




Historically, it did matter on some operating systems under some edge cases. These edge cases could exist in the future.

Here's an example, on SunOS in the Sun 3 era, there was an issue if a process used exec (or more traditionally fork and then exec), the subsequent new process would inherit the same memory footprint as the parent and it could not be shrunk. If a parent process allocated 1/2 gig of memory and didn't free it before calling exec, the child process would start using that same 1/2 gig (even though it wasn't allocated). This behavior was best exhibited by SunTools (their default windowing system), which was a memory hog. Every app that it spawned was created via fork/exec and inherited SunTools footprint, quickly filling up swap space.




I see the same problem as all scenario questions like this: What happens when the program changes, and suddenly that little memory leak is being called ten million times and the end of your program is in a different place so it does matter? If it's in a library then log a bug with the library maintainers, don't put a leak into your own code.




Its really not a leak if its intentional and its not a problem unless its a significant amount of memory, or could grow to be a significant amount of memory. Its fairly common to not cleanup global allocations during the lifetime of a program. If the leak is in a server or long running app, grows over time, then its a problem.






Links