¿Por qué lenguajes como C y C ++ no tienen recolección de basura, mientras que Java sí? [cerrado]

54

Bueno, sé que hay cosas como malloc / free for C, y new / using-a-destructor para la administración de memoria en C ++, pero me preguntaba por qué no hay "nuevas actualizaciones" en estos idiomas que permitan ¿El usuario tiene la opción de administrar la memoria manualmente o que el sistema lo haga automáticamente (recolección de basura)?

Un poco de una pregunta nueva, pero solo he estado en CS durante aproximadamente un año.

    
pregunta Dark Templar 14.10.2011 - 21:41

16 respuestas

68

La recolección de basura requiere estructuras de datos para rastrear las asignaciones y / o el conteo de referencias. Esto crea una sobrecarga en la memoria, el rendimiento y la complejidad del lenguaje. C ++ está diseñado para estar "cerca del metal", en otras palabras, toma el lado de mayor rendimiento de las características de compensación frente a la conveniencia. Otros lenguajes hacen que la compensación es diferente. Esta es una de las consideraciones al elegir un idioma, el énfasis que prefiera.

Dicho esto, hay muchos esquemas para el recuento de referencias en C ++ que son bastante ligeros y de alto rendimiento, pero están en bibliotecas, tanto comerciales como de código abierto, en lugar de ser parte del lenguaje en sí. El conteo de referencias para administrar el tiempo de vida del objeto no es lo mismo que la recolección de basura, pero aborda muchos de los mismos tipos de problemas, y se ajusta mejor al enfoque básico de C ++.

    
respondido por el kylben 06.09.2015 - 06:55
43

Estrictamente hablando, no hay administración de memoria en absoluto en el lenguaje C. malloc () y free () no son palabras clave en el idioma, sino solo funciones que se llaman desde una biblioteca. Esta distinción puede ser pedante ahora, porque malloc () y free () son parte de la biblioteca estándar de C, y serán proporcionados por cualquier implementación de C que cumpla con los estándares, pero esto no siempre fue cierto en el pasado.

¿Por qué querría un idioma sin estándar para la gestión de memoria? Esto se remonta a los orígenes de C como 'ensamblaje portátil'. Hay muchos casos de hardware y algoritmos que pueden beneficiarse de, o incluso requerir, técnicas especializadas de administración de memoria. Que yo sepa, no hay manera de desactivar completamente la administración de memoria nativa de Java y reemplazarla con la suya. Esto simplemente no es aceptable en algunas situaciones de alto rendimiento / recursos mínimos. C proporciona una flexibilidad casi completa para elegir exactamente qué infraestructura utilizará su programa. El precio pagado es que el lenguaje C proporciona muy poca ayuda para escribir el código correcto y libre de errores.

    
respondido por el Charles E. Grant 09.10.2011 - 00:12
31

La respuesta real es que la única forma de crear un mecanismo de recolección de basura seguro y eficiente es tener soporte a nivel de idioma para referencias opacas. (O, a la inversa, una falta de soporte a nivel de idioma para la manipulación directa de la memoria).

Java y C # pueden hacerlo porque tienen tipos de referencia especiales que no se pueden manipular. Esto le da al tiempo de ejecución la libertad de hacer cosas como mover objetos asignados en la memoria , lo cual 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 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 separado de "sobreviviente", y toda una generación de los objetos se desasigna a la vez.

Este enfoque tiene ventajas y desventajas: la ventaja es que las asignaciones de pila en un lenguaje que admite GC son tan rápidas como las asignaciones de pila en una lengua que no es compatible con GC, y la desventaja es que los objetos que necesitan realizar una limpieza antes de ser destruidos requieren un mecanismo separado (por ejemplo, la palabra clave using de C #) o su código de limpieza se ejecuta de manera no determinista.

Tenga en cuenta que una de las claves de un GC de alto rendimiento es que debe haber soporte de idioma para una clase especial de referencias. C no tiene este soporte de idioma y nunca lo hará; Como C ++ tiene una sobrecarga de operadores, 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 el CLR (el tiempo de ejecución .NET), tuvieron que inventar una nueva sintaxis para "referencias de estilo C #" (por ejemplo, Foo^ ) para distinguirlas de "C ++ - referencias de estilo "(por ejemplo, Foo& ).

Lo que C ++ tiene y lo que usan regularmente los programadores de C ++ es punteros inteligentes , que en realidad son solo un mecanismo de conteo de referencias. No consideraría que el recuento de referencias sea un GC "verdadero", pero proporciona muchos de los mismos beneficios, a costa de un rendimiento más lento que la administración de memoria manual o un 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 de idioma. C hizo una elección, C ++ hizo una elección que le permitía ser compatible con versiones anteriores de C mientras seguía ofreciendo 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 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 que sea más adecuada para el programa que esté intentando construir.

    
respondido por el Daniel Pryden 07.09.2015 - 01:02
26

Porque, cuando se usa el poder de C ++, no hay necesidad.

Herb Sutter: " no he escrito borrar en años. "

vea Escribiendo el código moderno de C ++: cómo C ++ ha evolucionado con los años 21:10

Puede sorprender a muchos programadores de C ++ con experiencia.

    
respondido por el Lior Kogan 08.10.2011 - 23:27
15

"Todo" un recolector de basura es un proceso que se ejecuta periódicamente para verificar si hay objetos sin referencia en la memoria y si hay borrados. (Sí, sé que esto es una gran simplificación). Esto no es una propiedad del lenguaje, sino el marco.

Hay recolectores de basura escritos para C y C ++ - este por ejemplo.

Una de las razones por las que uno no se ha "agregado" al idioma podría deberse al gran volumen de código existente que nunca lo usaría, ya que utilizan su propio código para administrar la memoria. Otra razón podría ser que los tipos de aplicaciones escritas en C y C ++ no necesitan la sobrecarga asociada con un proceso de recolección de basura.

    
respondido por el ChrisF 08.10.2011 - 23:09
12

C se diseñó en una época en que la recolección de basura era apenas una opción. También se destinó a usos en los que la recolección de basura no funcionaría en general: entornos de metal en tiempo real, con poca memoria y un mínimo soporte de tiempo de ejecución. Recuerde que C fue el lenguaje de implementación para el primer Unix, que se ejecutó en un pdp-11 con 64 * K * bytes de memoria. C ++ originalmente era una extensión de C: la elección ya se había hecho, y es muy difícil injertar la recolección de basura en un idioma existente. Es el tipo de cosas que se deben construir desde la planta baja.

    
respondido por el ddyer 09.10.2011 - 00:19
9

No tengo las citas exactas, pero tanto Bjarne como Herb Sutter dicen algo en la línea:

  

C ++ no necesita un recolector de basura, porque no tiene basura.

En C ++ moderno, usas punteros inteligentes y, por lo tanto, no tienes basura.

    
respondido por el ronag 08.10.2011 - 22:56
8

Usted pregunta por qué estos idiomas no se han actualizado para incluir un recolector de basura opcional.

El problema con la recolección de basura opcional es que no puede mezclar el código que usa los diferentes modelos. Es decir, si escribo un código que presupone que estás utilizando un recolector de basura, no puedes usarlo en tu programa que tiene la recolección de basura desactivada. Si lo haces, se filtrará por todas partes.

    
respondido por el Winston Ewert 09.10.2011 - 06:53
6

¿Te imaginas escribir un controlador de dispositivo en un lenguaje con recolección de basura? ¿Cuántos bits podrían aparecer en la línea mientras se ejecutaba el GC?

¿O un sistema operativo? ¿Cómo podría iniciar la ejecución de la recolección de basura incluso antes de iniciar el núcleo?

C está diseñado para tareas de hardware de bajo nivel cerca. ¿El problema? Es un lenguaje tan agradable que también es una buena opción para muchas tareas de nivel superior. Los zares de idiomas son conscientes de estos usos, pero deben ser compatibles con los requisitos de los controladores de dispositivos, el código integrado y los sistemas operativos como prioridad.

    
respondido por el James Anderson 14.10.2011 - 10:42
6

La respuesta breve y aburrida a esta pregunta es que es necesario que exista un lenguaje que no sea de recolección de basura para las personas que escriben los recolectores de basura. No es conceptualmente fácil tener un lenguaje que al mismo tiempo permita un control muy preciso sobre el diseño de la memoria y tiene un GC en funcionamiento en la parte superior.

La otra pregunta es por qué C y C ++ no tienen recolectores de basura. Bueno, sé que C ++ tiene un par de ellos, pero no son realmente populares porque se ven obligados a lidiar con un lenguaje que no fue diseñado para ser GC-ed en primer lugar, y las personas que todavía usan C ++ en esta edad no es realmente del tipo que pierde un GC.

Además, en lugar de agregar GC a un idioma antiguo no editado por GC, en realidad es más fácil crear un nuevo idioma que tenga la mayoría de la misma sintaxis a la vez que admite un GC. Java y C # son buenos ejemplos de esto.

    
respondido por el hugomg 04.10.2014 - 21:51
5

Hay varios problemas, incluyendo ...

  • Aunque GC se inventó antes de C ++, y posiblemente antes de C, tanto C como C ++ se implementaron antes de que los CG se aceptaran como prácticos.
  • No puede implementar fácilmente un lenguaje y una plataforma de GC sin un lenguaje subyacente que no sea de GC.
  • Aunque GC es demostrablemente más eficiente que el que no es GC para el código de aplicaciones típicas desarrollado en escalas de tiempo típicas, etc., hay problemas en los que un mayor esfuerzo de desarrollo es un buen compromiso y la administración de memoria especializada superará a un GC de propósito general. Además, C ++ es demostrablemente más eficiente que la mayoría de los lenguajes de GC incluso sin ningún esfuerzo de desarrollo adicional.
  • GC no es universalmente más seguro que el estilo CII RAII. RAII permite que los recursos que no sean memoria se limpien automáticamente, básicamente porque admite destructores confiables y oportunos. Estos no pueden combinarse con métodos de GC convencionales debido a problemas con los ciclos de referencia.
  • Los idiomas de GC tienen sus propios tipos característicos de fugas de memoria, particularmente en relación con la memoria que nunca se volverá a utilizar, pero donde existían referencias existentes que nunca se han anulado o sobrescrito. La necesidad de hacer esto explícitamente no es diferente en principio a la necesidad de delete o free explícitamente. El enfoque de GC aún tiene una ventaja, sin referencias colgantes, y el análisis estático puede detectar algunos casos, pero nuevamente, no hay una solución perfecta para todos los casos.

Básicamente, en parte se trata de la edad de los idiomas, pero de todos modos siempre habrá un lugar para los idiomas que no son de GC, incluso si es un poco nichey. Y en serio, en C ++, la falta de GC no es un gran problema: su memoria se gestiona de manera diferente, pero no está administrada.

Microsofts administrados C ++ tiene al menos cierta capacidad para mezclar GC y no GC en la misma aplicación, lo que permite una combinación de las ventajas de cada uno, pero no tengo la experiencia para decir qué tan bien funciona esto en la práctica.

Los enlaces de la prostitución a las respuestas mías relacionadas ...

respondido por el Steve314 23.05.2017 - 13:33
4

La recolección de basura es fundamentalmente incompatible con un lenguaje de sistemas utilizado para desarrollar controladores para hardware compatible con DMA.

Es totalmente posible que el único puntero a un objeto se almacene en un registro de hardware en algún periférico. Dado que el recolector de basura no sabría sobre esto, pensaría que el objeto era inalcanzable y lo recolectaría.

Este argumento es doble para compactar GC. Incluso si tuviera cuidado de mantener las referencias en memoria a los objetos utilizados por los periféricos de hardware, cuando el GC reubicó el objeto, no sabría cómo actualizar el puntero que se encuentra en el registro de configuración periférica.

Así que ahora necesitarías una mezcla de búferes DMA inmóviles y objetos administrados por GC, lo que significa que tienes todas las desventajas de ambos.

    
respondido por el Ben Voigt 15.10.2011 - 05:59
3

Porque, C & C ++ son lenguajes de nivel relativamente bajo destinados a fines generales, incluso, por ejemplo, para ejecutarse en un procesador de 16 bits con 1 MB de memoria en un sistema integrado, que no puede permitirse perder memoria con gc.

    
respondido por el Petruza 09.10.2011 - 06:38
2

Hay recolectores de basura en C ++ y C. No estoy seguro de cómo funciona esto en C, pero en C ++ puede aprovechar RTTI para descubrir dinámicamente el gráfico de objetos y usarlo para la recolección de basura.

Que yo sepa, no puedes escribir Java sin un recolector de basura. Una pequeña búsqueda mostró esto .

La diferencia clave entre Java y C / C ++ es que en C / C ++ la elección es siempre tuya, mientras que en Java a menudo no tienes opciones por diseño.

    
respondido por el back2dos 23.05.2017 - 14:40
2

Es un intercambio entre rendimiento y seguridad.

No hay garantía de que su basura se recolectará en Java, por lo que puede quedarse sin usar mucho espacio, mientras que la búsqueda de objetos sin referencia (es decir, basura) también lleva más tiempo que eliminar o liberar explícitamente una no utilizada. objeto.

La ventaja es, por supuesto, que uno puede construir un idioma sin punteros o sin pérdidas de memoria, por lo que es más probable que produzca el código correcto.

En ocasiones, puede haber una ligera ventaja 'religiosa' en estos debates. ¡Tenga cuidado!

    
respondido por el adrianmcmenamin 09.10.2011 - 21:36
1

Aquí hay una lista de problemas inherentes de GC, que lo hacen inutilizable en un lenguaje de sistema como C:

  • El GC debe ejecutarse por debajo del nivel del código de los objetos que administra. Simplemente no hay tal nivel en un kernel.

  • Un GC debe detener el código administrado de vez en cuando. Ahora piense qué pasaría si le hiciera eso a su núcleo. Todo el procesamiento en su máquina se detendría durante, por ejemplo, un milisegundo, mientras que el GC escanea todas las asignaciones de memoria existentes. Esto acabaría con todos los intentos de crear sistemas que funcionen bajo estrictos requisitos de tiempo real.

  • Un GC debe poder distinguir entre punteros y no punteros. Es decir, debe poder ver cada objeto de memoria existente y poder producir una lista de compensaciones donde se pueden encontrar sus punteros.

    Este descubrimiento debe ser perfecto: el GC debe poder perseguir todos los punteros que descubre. Si hace referencia a un falso positivo, es probable que se bloquee. Si no logra descubrir un falso negativo, es probable que destruya un objeto que aún esté en uso, bloquee el código administrado o corrompa silenciosamente sus datos.

    Esto requiere absolutamente que la información de tipo se almacene en cada objeto en existencia. Sin embargo, tanto C como C ++ permiten objetos de datos antiguos que no contienen información de tipo.

  • GC es una empresa intrínsecamente lenta. Los programadores que han sido socializados con Java pueden no darse cuenta de esto, pero los programas pueden ser mucho más rápidos cuando no están implementados en Java. Y uno de los factores que hacen que Java sea lento es GC. Esto es lo que impide que los lenguajes GCed como Java se utilicen en la supercomputación. Si su máquina cuesta un millón al año en consumo de energía, no desea pagar ni el 10% de eso por la recolección de basura.

C y C ++ son idiomas que se crean para admitir todos los posibles casos de uso. Y, como puede ver, muchos de estos casos de uso están excluidos por la recolección de basura. Por lo tanto, para admitir estos casos de uso, C / C ++ no puede ser recogida de basura.

    
respondido por el cmaster 06.09.2015 - 09:23

Lea otras preguntas en las etiquetas