¿Por qué se pierde la memoria en un programa de computadora?

¿Por qué se pierde la memoria en un programa?

Tenga en cuenta: este es un tratamiento muy simplificado del tema y está escrito para transmitir los conceptos generales y no todas las respuestas posibles.

Las pérdidas de memoria son causadas por una mala programación. La memoria en una computadora es un recurso finito. Todo programa útil necesita memoria para contener los valores que cambian (se denominan variables, porque su valor puede variar con el tiempo) a lo largo de la “vida útil” en la que se ejecuta. Casi todo sobre un programa de computadora consume algo de memoria. Cosas como la cantidad de notificaciones de mensajes que tiene (hablando de Quora), qué texto mostrar en la parte superior de la página web, listas de artículos, y así sucesivamente. Ahora, algún programador tiene que decirle a la computadora el tipo de variable de cada cosa, podría haber miles o más variables.

  • El programador le pide a la computadora que reserve algo de espacio para su variable. Si hay memoria disponible, la computadora le devolverá al programador una referencia a la memoria.
    • A veces no hay suficiente memoria y si el programador no presta atención a este hecho, su programa puede fallar al intentar acceder a la memoria que no ha sido asignada. En Windows, esto generalmente causa una falla de segmentación.
  • El programador puede usar esta variable durante el tiempo que lo necesite o hasta que se limpie automáticamente al salir de una función (este es otro tema largo “, en la programación de qué es una función, qué es un procedimiento, qué es una clase , qué es una unidad de compilación, etc. ”
    • A veces es imposible que la computadora sepa cuándo algo debería poder eliminarse de la memoria. Digamos que tiene “Cosa A” y se refiere a “Cosa B” que a cambio se refiere a “Cosa A”. La computadora ha determinado que debería ser capaz de eliminar “Thing A” de la memoria, por lo que verifica si hay algo más que se refiera a “Thing A” y ve que “Thing B” lo hace, por lo que decide “¡Vaya! No puedo eliminar “Cosa A” todavía. Esto se vuelve mucho más difícil cuando hay una larga cadena de “Cosas”
  • Luego, una vez que el programador haya terminado con la variable, debe pedirle a la computadora que recupere la memoria.
    • La mayoría de los programadores, después de varios años, se vuelven meticulosos al tratar de asegurarse de que devuelvan la memoria. Pero esta disciplina a menudo solo viene después de ser quemada varias veces. Algunos programadores siguen siendo descuidados.

¿Eso sucede más en dispositivos más antiguos?

Hay varias cosas que podrían hacer que esto parezca ser así, incluso si pudiera ser una observación defectuosa.

  • Los dispositivos más antiguos generalmente tienen menos memoria y, por lo tanto, mostrarían pérdidas de memoria más rápido que un dispositivo con más memoria (RAM no SSD o HD).
  • Los dispositivos más antiguos tienen versiones anteriores de su sistema operativo, que en realidad es solo un programa muy complicado. Todos los programas tienen errores (supongo que es posible que un programa pueda escribirse sin errores, pero ¿el sistema operativo no tiene errores? ¿El compilador no tiene errores? ¿Qué tal el hardware real en el que se ejecuta?
    • Tenga en cuenta que los sistemas operativos más antiguos ya no se actualizan, por lo que a veces pueden tener más errores que los nuevos.
  • Los programadores desperdician muchos recursos y, a medida que las nuevas computadoras salen con más espacio disponible, usan rápidamente todo lo que tienen disponible. Esto hace que la nueva versión del programa se ejecute más lentamente en máquinas antiguas (si es que pueden ejecutarse)

Podría hablar durante horas sobre este tema, pero espero haberle dado al menos una idea de lo que está sucediendo.

Las mismas razones por las que los juguetes se escapan de una sala de juegos familiar o porque el dinero se escapa de un fondo: alguien no está devolviendo lo que juega.

Clásicamente, esto proviene de construir una estructura significativa y compleja (una estructura que contiene estructuras, que contienen listas de estructuras, que apuntan a estructuras, que pueden contener la estructura original …) y no ser exhaustivos al desarmarla.

La solución a la mayoría de estos problemas ha sido introducir la recolección de basura. Language Runtime supervisa si una estructura está en uso o cuenta el número de partes del programa que “conocen” la estructura, y toma decisiones que ya no vale la pena mantener y, por lo tanto, se elimina, la próxima vez que la basura sale. Esto resuelve el problema básico al quitar (en su mayoría) el proceso de desasignación de las manos, pero introduce un nuevo problema al proporcionar a los programadores formas de “burlar” al recolector de basura, y los programadores hacen exactamente eso, tanto intencionalmente (y luego no logran administrarlo) ) y accidentalmente.

Hay una investigación constante sobre cómo hacer esto mejor. Hasta donde yo sé, no hay dos sistemas que tengan el mismo algoritmo de recolección de basura, porque las ideas siempre están siendo modificadas. Pero también hay lenguajes como Rust, que tiene un modelo de “propiedad” que hace que sea muy difícil dejar objetos a menos que sea absolutamente necesario, a expensas de enfurecer a los recién llegados que esperan poder pasar sus objetos; no hay recolección de basura, pero tiene muchos de los mismos resultados con menos agujeros.

Todo se reduce a que el compilador y el tiempo de ejecución tienen muchos problemas para adivinar si alguna vez volverás a usar algo. Y, como tratar con un niño pequeño, no se atreverá a tirar algo si no está del todo claro, porque lo sabrá por el resto de su vida. Por lo tanto, los programadores deben asumir la carga y la mayoría de los programadores … realmente no les importa. Estamos acostumbrados a que los programas se apaguen, eventualmente, y el sistema operativo recupere toda la memoria, por lo que cuando se supone que los programas se ejecutan para siempre (servidores), las cosas se quedan atrás.

En pocas palabras, ocurre cuando un bloque de memoria previamente asignado (creado usando “nuevo” o “malloc”) ya no es necesario, pero no se devuelve al montón (desde donde se asigna toda la memoria). Esto crea un bloque de memoria “huérfano” que no está siendo administrado por ninguna entidad, y por lo tanto ese bloque de memoria efectivamente “desaparece” del sistema en el sentido de que nadie puede reutilizarlo. Esta es una pérdida de memoria.

La razón por la que suceden es que a veces un bloque de memoria asignado no se libera (se devuelve al montón como memoria disponible) después de que ya no se necesita. Con el tiempo, el “código de error” que permitió que esto sucediera a menudo seguirá asignando bloques de memoria una y otra vez, pero no puede devolver ninguno de ellos al montón para que puedan reutilizarse. Es por eso que la memoria “pierde” en un programa de computadora.

Para completar una tarea adicional, los programas a menudo necesitan solicitar [también conocido como asignar] más memoria de la que usan para las tareas actuales. Después de completar la tarea adicional, el programa desasigna la memoria. Si el programa no puede desasignar la memoria, y luego vuelve a realizar la misma tarea, asignará nueva memoria [no utilizada] en lugar de reutilizar la memoria que debería haber sido desasignada cuando la tarea se completó la vez anterior.

Muchos lenguajes de programación modernos, incluido Java, tienen lo que se llama “recolección de basura”, por lo que el programa busca memoria que debería haberse desasignado y luego lo desasigna. Si la recolección de basura falla, se produce una pérdida de memoria. Un tipo de pérdida de memoria (una ocurrencia rara en cualquier sistema operativo decente, excluido Windows) involucra un programa que finaliza sin desasignar la memoria que estaba usando.