La verdadera respuesta es que la única forma de crear un mecanismo de recolección de basura seguro y eficiente es tener soporte a nivel de lenguaje para referencias opacas. (O, por el contrario, la falta de soporte a nivel de lenguaje para la manipulación directa de la memoria).
Java y C # pueden hacerlo porque tienen tipos de referencia especiales que no pueden ser manipulados. Esto le da al tiempo de ejecución la libertad de hacer cosas como mover objetos asignados en la memoria , que es crucial para una implementación de GC de alto rendimiento.
Para el registro, ninguna implementación moderna de GC utiliza el recuento de referencias , por lo que es completamente una pista falsa. Los GC modernos utilizan la colección generacional, donde las nuevas asignaciones se tratan esencialmente de la misma manera que las asignaciones de pila están en un lenguaje como C ++, y luego periódicamente los objetos recién asignados que aún están vivos se mueven a un espacio "sobreviviente" separado, y una generación entera de objetos se desasigna a la vez.
Este enfoque tiene ventajas y desventajas: la ventaja es que las asignaciones de montón en un lenguaje que admite GC son tan rápidas como las asignaciones de pila en un lenguaje que no admite GC, y la desventaja es que los objetos que necesitan realizar una limpieza antes de ser destruidos requieren un mecanismo separado (por ejemplo, la using
palabra clave de C # ) o de lo contrario su código de limpieza se ejecuta de forma no determinista.
Tenga en cuenta que una clave para un GC de alto rendimiento es que debe haber soporte de idioma para una clase especial de referencias. C no tiene soporte para este lenguaje y nunca lo tendrá; debido a que C ++ tiene una sobrecarga del operador, podría emular un tipo de puntero GC'd, aunque tendría que hacerse con cuidado. De hecho, cuando Microsoft inventó su dialecto de C ++ que se ejecutaría bajo CLR (el tiempo de ejecución de .NET), tuvieron que inventar una nueva sintaxis para "referencias de estilo C #" (por ejemplo Foo^
) para distinguirlas de "referencias de estilo C ++" (por ejemplo Foo&
)
Lo que sí tiene C ++, y lo que usan regularmente los programadores de C ++, son punteros inteligentes , que en realidad son solo un mecanismo de conteo de referencias. No consideraría el conteo de referencias como GC "verdadero", pero proporciona muchos de los mismos beneficios, a costa de un rendimiento más lento que la gestión de memoria manual o el GC verdadero, pero con la ventaja de la destrucción determinista.
Al final del día, la respuesta realmente se reduce a una función de diseño del lenguaje. C hizo una elección, C ++ hizo una elección que le permitía ser compatible con versiones anteriores de C y al mismo tiempo proporcionar alternativas que son lo suficientemente buenas para la mayoría de los propósitos, y Java y C # hicieron una elección diferente que es incompatible con C pero que también es lo suficientemente buena para La mayoría de los propósitos. Desafortunadamente, no hay una bala de plata, pero estar familiarizado con las diferentes opciones disponibles le ayudará a elegir la correcta para cualquier programa que esté tratando de construir actualmente.