usar memoria funcion estatica dinámicos dinamica como cadena arreglos memory-management garbage-collection free

memory management - memoria - ¿Por qué no se permite free() en los idiomas recolectados en la basura?



memoria estatica en c (11)

Estaba leyendo la entrada de C# en Wikipedia, y encontré:

La memoria gestionada no puede ser liberada explícitamente; En su lugar, es automáticamente recogida de basura.

¿Por qué es que en los idiomas con administración automática de memoria, la administración manual ni siquiera está permitida ? Puedo ver que en la mayoría de los casos no sería necesario, pero ¿no sería útil cuando tiene poca memoria y no quiere confiar en que el GC sea inteligente?


¿Por qué es que en los idiomas con administración automática de memoria, la administración manual ni siquiera está permitida? Puedo ver que en la mayoría de los casos no sería necesario, pero ¿no sería útil cuando tiene poca memoria y no quiere confiar en que el GC sea inteligente?

En la gran mayoría de los idiomas y máquinas virtuales recolectados, no tiene sentido ofrecer una función free , aunque casi siempre puede usar el FFI para asignar y liberar memoria no administrada fuera de la VM administrada, si así lo desea.

Hay dos razones principales por las cuales free ausencia de los idiomas recolectados en la basura es free :

  1. Seguridad de la memoria.
  2. No hay punteros.

Con respecto a la seguridad de la memoria, una de las principales motivaciones de la administración automática de la memoria es eliminar la clase de errores causados ​​por la administración manual incorrecta de la memoria. Por ejemplo, si la administración de memoria manual llama free con el mismo puntero dos veces o con un puntero incorrecto, se pueden dañar las estructuras de datos propias del administrador de memoria y causar bloqueos no deterministas más adelante en el programa (cuando el administrador de memoria alcance sus datos corruptos). Esto no puede suceder con la administración automática de la memoria, pero la exposición free abriría nuevamente esta lata de gusanos.

Con respecto a los punteros, la función free libera un bloque de memoria asignada en una ubicación especificada por un puntero al administrador de memoria. Los idiomas y máquinas virtuales recolectados en la basura reemplazan los punteros con un concepto más abstracto llamado referencias. La mayoría de los GC de producción se están moviendo, lo que significa que el código de alto nivel contiene una referencia a un valor u objeto, pero la ubicación subyacente en la memoria puede cambiar ya que la VM es capaz de mover los bloques de memoria asignados sin que el lenguaje de alto nivel lo sepa. Esto se utiliza para compactar el montón, evitando la fragmentación y mejorando la localidad.

Así que hay buenas razones para no tener free cuando tienes un GC.


¿Por qué querrías usar free() ? Supongamos que tiene una gran cantidad de memoria que desea desasignar.

Una forma de hacerlo es llamar al recolector de basura, o dejar que se ejecute cuando el sistema lo desee. En ese caso, si no se puede acceder a la gran parte de la memoria, se desasignará. (Los recolectores de basura modernos son muy inteligentes). Eso significa que, si no se desasignó, todavía se podría acceder.

Por lo tanto, si puede deshacerse de él con free() pero no con el recolector de basura, algo todavía puede acceder a ese fragmento (y no a través de un puntero débil si el idioma tiene el concepto), lo que significa que queda con el idioma del idioma. equivalente a un puntero colgante.

El lenguaje puede defenderse contra los dobleces o intentar liberar la memoria no asignada, pero la única forma de evitar los punteros es suprimiendo free() o modificando su significado para que ya no tenga uso.


Curiosamente, usted tiene acceso al recolector de basura a través de System.GC - Aunque de todo lo que he leído, es muy recomendable que permita que el GC se administre solo.

Una vez, un proveedor tercero me recomendó que usara las siguientes 2 líneas para tratar un problema de recolección de basura con una DLL o un objeto COM o algo parecido:

// Force garbage collection (cleanup event objects from previous run.) GC.Collect(); // Force an immediate garbage collection of all generations GC.GetTotalMemory(true);

Dicho esto, no me molestaría con System.GC a menos que supiera exactamente qué estaba pasando debajo del capó. En este caso, el consejo del proveedor tercero "solucionó" el problema con el que estaba tratando con respecto a su código. Pero no puedo evitar preguntarme si esto fue realmente una solución para su código roto ...


En los sistemas que permiten que los objetos se liberen manualmente, las rutinas de asignación tienen que buscar en una lista de áreas de memoria liberada para encontrar algo de memoria libre. En un sistema basado en la recolección de basura, cualquier memoria libre disponible de inmediato estará al final del montón. En general, es más rápido y más fácil para el sistema ignorar las áreas de memoria no utilizadas en el medio del montón de lo que sería tratar de asignarlas.


Llamar a GC.Collect es casi siempre mejor que tener un método free explícito. Hacer llamadas free tendría sentido para los punteros / referencias de objetos a los que se hace referencia desde ninguna parte. Eso es algo que es propenso a errores, ya que existe la posibilidad de que su llamada sea free para el tipo de indicador incorrecto.

Cuando el entorno de ejecución hace referencia al monitoreo de conteo por usted, sabe qué punteros se pueden liberar de forma segura y cuáles no, por lo que dejar que el GC decida qué memoria se puede liberar evita una clase de errores de errores. Uno podría pensar en una implementación en tiempo de ejecución con GC y free donde la llamada free para un solo bloque de memoria podría ser mucho más rápida que ejecutar un GC.Collect completo (pero no espere que liberar cada bloque de memoria posible "a mano" sea más rápido que el GC). Pero creo que los diseñadores de C #, CLI (y otros lenguajes con recolectores de basura como Java) han decidido favorecer la robustez y la seguridad sobre la velocidad aquí.


Los lenguajes con gestión automática de memoria están diseñados para proporcionar garantías sustanciales de seguridad de memoria que no se pueden ofrecer en presencia de ninguna administración de memoria manual.

Entre los problemas prevenidos se encuentran

  • Doble free() s
  • Llamar a free() en un puntero a la memoria que no posee, lo que lleva a un acceso ilegal en otros lugares
  • Llamar a free() en un puntero que no era el valor de retorno de una función de asignación, como tomar la dirección de algún objeto en la pila o en medio de una matriz u otra asignación.
  • Desreferenciación de un puntero a la memoria que ya ha sido free() d

Además, la administración automática puede resultar en un mejor rendimiento cuando el GC mueve objetos en vivo a un área consolidada. Esto mejora la localidad de referencia y, por tanto, el rendimiento del caché.


Muchas de las otras respuestas brindan buenas explicaciones de cómo funciona el GC y cómo debe pensar al programar contra un sistema de tiempo de ejecución que proporciona un GC.

Me gustaría agregar un truco que trato de tener en cuenta al programar en lenguajes GC''d. La regla es esta: "Es importante eliminar los punteros lo antes posible". Al eliminar los punteros, quiero decir que ya no señalo objetos que ya no usaré. Por ejemplo, esto se puede hacer en algunos idiomas estableciendo una variable en Null. Esto puede verse como una sugerencia para el recolector de basura de que está bien recopilar este objeto, siempre que no haya otros punteros a él.


No puedo decir que es la respuesta, pero una que me viene a la mente es que si puedes free , puedes accidentalmente duplicar un puntero / referencia o, peor aún, usar uno después de gratis. Lo que elimina el punto principal de usar lenguajes como c # / java / etc.

Por supuesto, una posible solución sería tener su argumento free por su referencia y establecerlo en null después de la liberación. Pero entonces, ¿qué pasa si pasan un r-value como este: free(whatever()) . Supongo que podría tener una sobrecarga para las versiones de valor r, pero ni siquiera sé si c # admite tal cosa :-P.

Al final, incluso eso sería insuficiente porque, como se ha señalado, puede tener varias referencias al mismo objeto. Establecer uno en null no haría nada para evitar que los demás accedan al objeto ahora desasignado.


Se permite la gestión manual. Por ejemplo, en Ruby GC.start liberará todo lo que pueda liberarse, aunque no puedes liberar cosas individualmente.


Si se encuentra en una situación en la que "no desea confiar en que el GC sea inteligente", lo más probable es que haya elegido incorrectamente el marco para su tarea. En .net puede manipular GC un poco ( http://msdn.microsoft.com/library/system.gc.aspx ), en Java no está seguro.

Creo que no puedes llamar gratis porque empiezas a hacer una tarea de GC. La eficiencia de GC puede garantizarse de alguna manera en general cuando hace las cosas de la manera que mejor las encuentra y las hace cuando lo decide. Si los desarrolladores interfieren con GC, podría disminuir su eficiencia general.


La recolección de basura aplica el tipo de seguridad de un asignador de memoria garantizando que las asignaciones de memoria nunca sean alias. Es decir, si un fragmento de memoria se está viendo actualmente como un tipo T , el asignador de memoria puede garantizar (con la recolección de elementos no utilizados) que mientras esa referencia esté viva, siempre se referirá a una T Más específicamente, significa que el asignador de memoria nunca devolverá esa memoria como un tipo diferente.

Ahora, si un asignador de memoria permite el uso free() y utiliza la recolección de elementos no utilizados, debe asegurarse de que nadie más haga referencia a la memoria que usted free() . en otras palabras, que la referencia que usted pasa a free() es la única referencia a esa memoria. La mayoría de las veces es prohibitivo hacerlo dado un llamado arbitrario a free() , por lo que la mayoría de los asignadores de memoria que usan recolección de basura no lo permiten.

Eso no quiere decir que no sea posible; Si pudiera expresar un tipo de referencia única, podría administrarlo manualmente. Pero en ese momento sería más fácil dejar de usar un lenguaje GC o simplemente no preocuparse por eso.