Desventajas de la gestión de memoria basada en el alcance


38

Realmente me gusta la administración de memoria basada en el alcance (SBMM), o RAII , ya que la comunidad C ++ se refiere más comúnmente (¿confusamente?). Hasta donde yo sé, a excepción de C ++ (y C), no hay otro lenguaje convencional en uso hoy en día que haga de SBMM / RAII su mecanismo principal de administración de memoria, y en su lugar prefieren usar la recolección de basura (GC).

Esto me parece bastante confuso, ya que

  1. SBMM hace que los programas sean más deterministas (puede saber exactamente cuándo se destruye un objeto);
  2. en los lenguajes que usan GC, a menudo tiene que hacer una gestión manual de recursos (vea cerrar archivos en Java, por ejemplo), lo que en parte anula el propósito de GC y también es propenso a errores;
  3. La memoria de almacenamiento dinámico también puede (muy elegantemente, imo) estar unida al alcance (ver std::shared_ptren C ++).

¿Por qué no se usa más SBMM? ¿Cuáles son sus desventajas?


1
Algunas desventajas (especialmente con respecto a la velocidad) se discuten en Wikipedia: en.wikipedia.org/wiki/…
Philipp

2
El problema de la gestión manual de recursos de Java es un efecto secundario de no garantizar que finalize()se llamará al método de un objeto antes de la recolección de basura. En efecto, esto crea la misma clase de problema que se supone que debe resolver la recolección de basura.
Blrfl

77
@Blrfl Tonterías. Sería preferible la gestión de recursos "manual" (para recursos distintos a la memoria, obviamente) incluso si ese "problema" no existiera, porque el GC puede ejecutarse mucho tiempo después de que el recurso no se use, o incluso no funcionar. Eso no es problema para la memoria , y la gestión de la memoria es todo lo que se supone que debe resolver la recolección de basura.

44
por cierto. Me gusta referirme a él como SBRM, ya que puede usar el mismo mecanismo para administrar los recursos en general, no solo la memoria.
PlasmaHH

Respuestas:


27

Comencemos por postular que la memoria es, con diferencia (docenas, cientos o incluso miles de veces) más común que todos los demás recursos combinados. Cada variable, objeto, miembro de objeto necesita un poco de memoria asignada y liberada más adelante. Por cada archivo que abra, crea decenas de millones de objetos para almacenar los datos extraídos del archivo. Cada secuencia TCP va junto con un número ilimitado de cadenas de bytes temporales creadas para escribirse en la secuencia. ¿Estamos en la misma página aquí? Excelente.

Para que RAII funcione (incluso si tiene punteros inteligentes listos para cada caso de uso bajo el sol), debe obtener la propiedad correcta. Debe analizar quién debe poseer este o aquel objeto, quién no debe hacerlo y cuándo debe transferirse la propiedad de A a B. Claro, puede usar la propiedad compartida para todo , pero entonces estaría emulando un GC a través de punteros inteligentes. En ese momento, es mucho más fácil y rápido incorporar el GC al lenguaje.

La recolección de basura lo libera de esta preocupación por el recurso más utilizado, la memoria. Claro, aún necesita tomar la misma decisión para otros recursos, pero esos son mucho menos comunes (ver arriba), y la propiedad complicada (por ejemplo, compartida) también es menos común. La carga mental se reduce significativamente.

Ahora, nombra algunos inconvenientes para hacer que se recojan todos los valores. Sin embargo, la integración de GC y tipos de valores seguros para la memoria con RAII en un idioma es extremadamente difícil, por lo que ¿quizás sea mejor migrar estas compensaciones por otros medios?

La pérdida de determinismo resulta no ser tan mala en la práctica, porque solo afecta la vida del objeto determinista . Como se describe en el siguiente párrafo, la mayoría de los recursos (aparte de la memoria, que es abundante y puede reciclarse de manera bastante perezosa) no están sujetos a la vida útil de los objetos en estos idiomas. Hay algunos otros casos de uso, pero son raros en mi experiencia.

Su segundo punto, la gestión manual de recursos, se aborda hoy en día a través de una declaración que realiza una limpieza basada en el alcance, pero no combina esta limpieza con el tiempo de vida del objeto (por lo tanto, no interactúa con el GC y la seguridad de la memoria). Esto está usingen C #, withen Python, try-with-resources en versiones recientes de Java.


1
Esto no explica por qué los modelos no deterministas como GC deberían ser superiores a los deterministas. usinglas declaraciones solo son posibles localmente. Es imposible limpiar los recursos contenidos en las variables miembro de esa manera.
Philipp

8
@Philipp La propiedad compartida de todo es un GC, solo uno muy pobre. Si toma "propiedad compartida" para implicar el recuento de referencias, dígalo, pero mantenga la discusión sobre los ciclos en los comentarios sobre la respuesta de amon. Tampoco estoy seguro de si el recuento de referencias es determinista en el sentido en que OP está interesado (los objetos se liberan lo antes posible, descontando ciclos, pero a menudo no se puede saber cuándo es al mirar el programa). Además, el conteo de referencias para todo es lento, mucho más lento que un GC de rastreo moderno.

16
usinges una broma en comparación con RAII, para que lo sepas.
DeadMG

3
@Philipp, describa su métrica para "superior". Es cierto que la gestión de memoria manual es más rápida en tiempo de ejecución para tratar con la gestión de memoria. Sin embargo, el costo del software no puede juzgarse únicamente por el tiempo de CPU dedicado solo a la administración de memoria.
ArTs

2
@ ARTs: Ni siquiera necesariamente estaría de acuerdo con esto. RAII viene con el requisito de que un objeto debe ser destruido cuando sale del alcance. Entonces, se requiere un bucle para hacer n destrucciones de objetos. Bajo un GC generacional moderno, esas destrucciones podrían diferirse hasta el final del ciclo, o incluso más tarde, y realizar una sola operación para destruir cientos de iteraciones de memoria. Un GC puede ser muy muy rápido en sus buenos casos.
Phoshi

14

RAII también se deduce de la gestión automática de memoria de conteo de referencias, por ejemplo, como la utilizada por Perl. Si bien el recuento de referencias es fácil de implementar, determinista y bastante eficaz, no puede tratar con referencias circulares (causan una fuga), por lo que no se usa comúnmente.

Los lenguajes recolectados de basura no pueden usar RAII directamente, pero a menudo ofrecen sintaxis con un efecto equivalente. En Java, tenemos la declaración try-with-ressource

try (BufferedReader br = new BufferedReader(new FileReader(path))) { ... }

que llama automáticamente .close()al recurso a la salida del bloque. C # tiene la IDisposableinterfaz, que permite .Dispose()que se llame al salir de una using (...) { ... }declaración. Python tiene la withdeclaración:

with open(filename) as f:
    ...

que funciona de manera similar. En un giro interesante sobre esto, el método de apertura de archivos de Ruby recibe una devolución de llamada. Una vez que se ha ejecutado la devolución de llamada, el archivo se cierra.

File.open(name, mode) do |f|
    ...
end

Creo que Node.js usa la misma estrategia.


44
El uso de funciones de orden superior para la gestión de recursos se remonta mucho antes de Ruby. En Lisps, es bastante común tener, por ejemplo, with-open-filehandlefunciones que abren el archivo, lo ceden a una función y al regresar de la función cierran el archivo nuevamente.
Jörg W Mittag

44
El argumento de referencia cíclica es bastante común, pero ¿cuán importante es realmente? Las referencias cíclicas pueden mitigarse utilizando punteros débiles si la propiedad es clara.
Philipp

2
@Philipp Cuando usa el conteo de referencias, la propiedad generalmente no está clara. Además, esta respuesta habla de idiomas que usan el recuento de referencias de forma exclusiva y automática, por lo que las referencias débiles no existen o son mucho más difíciles de usar que las referencias fuertes.

3
Las estructuras de datos cíclicos de @Philipp son muy raras, a menos que esté trabajando con gráficos complicados de todos modos. Los punteros débiles no ayudan en un gráfico de objeto cíclico general, aunque ayudan en casos más comunes como los punteros principales en un árbol. Una buena solución es mantener un objeto de contexto que represente la referencia a todo el gráfico y gestione la destrucción. El recuento no es un factor decisivo, pero requiere que el programador sea muy consciente de sus restricciones. Es decir, tiene un costo cognitivo ligeramente mayor que el GC.
amon

1
Una razón importante por la que rara vez se usa el conteo de referencias es que a menudo es más lento que el GC, a pesar de su simplicidad.
Rufflewind

14

En mi opinión, la ventaja más convincente de la recolección de basura es que permite la componibilidad . La corrección de la administración de memoria es una propiedad local en el entorno de recolección de basura. Puede ver cada parte de forma aislada y determinar si puede perder memoria. Combine cualquier número de partes con corrección de memoria y se mantendrán correctas.

Cuando confía en el recuento de referencias, pierde esa propiedad. Si su aplicación puede perder memoria se convierte en una propiedad global de toda la aplicación con recuento de referencias. Cada nueva interacción entre partes tiene la posibilidad de usar la propiedad incorrecta y romper la administración de memoria.

Tiene un efecto muy visible en el diseño de programas en los diferentes idiomas. Los programas en los lenguajes GC tienden a ser un poco más sopas de objetos con muchas interacciones, mientras que en los lenguajes sin GC uno tiende a preferir partes estructuradas con interacciones estrictamente controladas y limitadas entre ellos.


1
La corrección solo es componible si los objetos solo contienen referencias en su propio nombre, y no en nombre de los objetivos de esas referencias. Una vez que cosas como las notificaciones entran en la mezcla (Bob tiene una referencia a Joe porque Joe le pidió a Bob que le avisara cuando sucedió algo y Bob prometió hacerlo, pero Bob no se preocupa por Joe), la corrección de GC a menudo requiere una gestión de recursos con alcance [implementado manualmente en muchos casos, ya que los sistemas GC carecen de la automatización de C ++].
supercat

@supercat: "La corrección de GC a menudo requiere una gestión de recursos con ámbito". Eh? El alcance solo existe en el código fuente y el GC solo existe en tiempo de ejecución (y, por lo tanto, es completamente ajeno a la existencia del alcance).
Jon Harrop

@ JonHarrop: Estaba usando el término "alcance" en el mismo sentido que un "puntero de alcance" de C ++ [la vida útil del objeto debería ser la del contenedor que lo contiene], ya que ese es el uso que implica la pregunta original. Mi punto es que los objetos crean referencias potencialmente duraderas a sí mismos para propósitos tales como recibir eventos que pueden no ser componibles en un sistema puramente GC. Para ser correctos, ciertas referencias deben ser fuertes y ciertas referencias deben ser débiles, y qué referencias deben ser las que dependerán de cómo se use un objeto. Por ejemplo ...
supercat

... supongamos que los objetos Fred y Barney se registran para recibir notificaciones cada vez que se modifica algo en un determinado directorio. El controlador de Fred no hace más que incrementar un contador cuyo valor puede informar a pedido, pero para el que no tiene otro uso. El controlador de Barney abrirá una nueva ventana si se modifica un determinado archivo. Para ser correcto, Fred debería estar suscrito con un evento débil, pero el de Barney debería ser fuerte, pero el objeto del temporizador no tendrá forma de saberlo.
supercat

@supercat: Correcto. Yo no diría que eso sucede "a menudo". Solo lo he encontrado una vez en 30 años de programación.
Jon Harrop

7

Los cierres son una característica esencial de casi todos los idiomas modernos. Son muy fáciles de implementar con GC y muy difíciles (aunque no imposibles) de acertar con RAII, ya que una de sus características principales es que le permiten abstraer durante la vida útil de sus variables.

C ++ solo los obtuvo 40 años después de que todos los demás lo hicieran, y a mucha gente inteligente le costó mucho trabajo hacerlos bien. En contraste, muchos lenguajes de scripting diseñados e implementados por personas con cero conocimiento en el diseño e implementación de lenguajes de programación los tienen.


9
No creo que los cierres en C ++ sean un buen ejemplo. Las lambdas en C ++ 11 son solo azúcar sintáctica para las clases de functor (que son anteriores a C ++ 11 significativamente), y son igualmente inseguras para la memoria: si captura algo por referencia y llama al cierre después de que esa cosa se muera, simplemente obtienes UB, al igual que mantener una referencia más larga que válida. El hecho de que aparecieran 40 años tarde se debe a un reconocimiento tardío de la PF, no a descubrir cómo hacerlos seguros. Y aunque diseñarlos fue ciertamente una tarea enorme, dudo que la mayor parte del esfuerzo se haya dedicado a consideraciones de por vida.

Estoy de acuerdo con delnan: C ++ no obtuvo los cierres correctos: debe programarlos con mucho cuidado si no desea obtener un volcado de núcleo cuando los invoca.
Giorgio

2
@delnan: captura por referencia lambda tiene muy intencionalmente esa [&]sintaxis. Cualquier programador de C ++ ya asocia el &signo con referencias y conoce referencias obsoletas.
MSalters

2
@MSalters ¿Cuál es tu punto? He dibujado la conexión de referencia yo mismo. No dije que las lambdas de C ++ son excepcionalmente inseguras, dije que son exactamente tan inseguras como las referencias. No argumentaba que las lambdas de C ++ eran malas, argumentaba en contra de la afirmación de esta respuesta (que C ++ tenía cierres muy tarde porque tenían que descubrir cómo hacerlo correctamente).

5
  1. SBMM hace que los programas sean más deterministas (puede saber exactamente cuándo se destruye un objeto);

Para la mayoría de los programadores, el sistema operativo no es determinista, su asignador de memoria no es determinista y la mayoría de los programas que escriben son concurrentes y, por lo tanto, inherentemente no deterministas. Agregar la restricción de que un destructor se llama exactamente al final del alcance en lugar de un poco antes o un poco después no es un beneficio práctico significativo para la gran mayoría de los programadores.

  1. en los lenguajes que usan GC, a menudo tiene que hacer una gestión manual de recursos (vea cerrar archivos en Java, por ejemplo), lo que en parte anula el propósito de GC y también es propenso a errores;

Ver usingen C # y useen F #.

  1. la memoria de almacenamiento dinámico también puede (muy elegantemente, imo) estar vinculada al alcance (vea std :: shared_ptr en C ++).

En otras palabras, podría tomar el montón que es una solución de propósito general y cambiarlo para que solo funcione en un caso específico que sea seriamente limitante. Eso es cierto, por supuesto, pero inútil.

¿Por qué no se usa más SBMM? ¿Cuáles son sus desventajas?

SBMM limita lo que puede hacer:

  1. SBMM crea el problema del funarg ascendente con los cierres léxicos de primera clase, por lo que los cierres son populares y fáciles de usar en lenguajes como C #, pero raros y difíciles en C ++. Tenga en cuenta que existe una tendencia general hacia el uso de construcciones funcionales en la programación.

  2. SBMM requiere destructores e impiden las llamadas de cola agregando más trabajo por hacer antes de que una función pueda regresar. Las llamadas de cola son útiles para máquinas de estado extensibles y son proporcionadas por cosas como .NET.

  3. Algunas estructuras de datos y algoritmos son notoriamente difíciles de implementar usando SBMM. Básicamente, en cualquier lugar donde los ciclos ocurren naturalmente. En particular, los algoritmos gráficos. Efectivamente terminas escribiendo tu propio GC.

  4. La programación concurrente es más difícil porque el flujo de control y, por lo tanto, la vida útil de los objetos son inherentemente no deterministas aquí. Las soluciones prácticas en los sistemas de transmisión de mensajes tienden a ser una copia profunda de los mensajes y el uso de vidas excesivamente largas.

  5. SBMM mantiene los objetos vivos hasta el final de su alcance en el código fuente, que a menudo es más largo de lo necesario y puede ser mucho más de lo necesario. Esto aumenta la cantidad de basura flotante (objetos inalcanzables que esperan ser reciclados). Por el contrario, el rastreo de recolección de basura tiende a liberar objetos poco después de que la última referencia a ellos desaparezca, lo que puede ser mucho antes. Consulte Mitos sobre la gestión de la memoria: rapidez .

SBMM es tan limitante que los programadores necesitan una ruta de escape para situaciones en las que no se pueden anidar vidas. En C ++, shared_ptrofrece una ruta de escape, pero puede ser ~ 10 veces más lenta que el rastreo de recolección de basura . Por lo tanto, usar SBMM en lugar de GC pondría a la mayoría de las personas equivocadas la mayor parte del tiempo. Sin embargo, eso no quiere decir que sea inútil. SBMM sigue siendo valioso en el contexto de sistemas y programación integrada donde los recursos son limitados.

FWIW te gustaría echar un vistazo a Forth y Ada, y leer sobre el trabajo de Nicolas Wirth.


1
Si dices qué partes puedo elaborar o citar artículos.
Jon Harrop

2
¿Cuán relevante es ser 10 veces más lento en algunos casos de uso poco frecuente en lugar de ser omnipresente en todos los casos de uso? C ++ tiene unique_ptr y para la mayoría de los propósitos es suficiente. Además de eso, en lugar de atacar RAII a través de C ++ (un lenguaje que muchos aman odiar por ser un idioma arcaico), si vas a atacar RAII a través de atacar un idioma, prueba con un hermano menor de la familia RAII, Rust, por ejemplo. Rust básicamente hace todo bien porque C ++ se equivocó, mientras que hace la mayoría de las cosas bien que C ++ también se equivocó. Además, el "uso" le proporciona un conjunto muy limitado de casos de uso e ignora la composición.
user1703394

2
"¿Cuán relevante es ser 10 veces más lento en algunos casos de uso poco frecuente en lugar de ser omnipresente en todos los casos de uso?". En primer lugar, ese es un argumento circular: shared_ptrsolo es raro en C ++ porque es muy lento. En segundo lugar, se trata de una comparación de manzanas y naranjas (como ya mostró el artículo que cité) porque shared_ptres muchas veces más lenta que un GC de producción. En tercer lugar, los GC no son omnipresentes y se evitan en software como LMax y el motor FIX de Rapid Addition.
Jon Harrop

1
@ Jon Harrop, si no has podido, por favor, ilumíname ¿Qué receta mágica has usado durante más de 30 años para mitigar los efectos transitivos del uso de recursos profundos? Sin una receta mágica después de más de 30 años, solo podría concluir que debes haber atribuido erróneamente que te mordió por otras causas.
user1703394

1
@Jon Harrop, shared_ptr no es raro porque es lento, es raro porque en un sistema de diseño decente la necesidad de 'propiedad compartida' es rara.
user1703394

4

Mirando un índice de popularidad como TIOBE (que es discutible, por supuesto, pero supongo que para su tipo de pregunta está bien usar esto), primero ve que ~ 50% de los 20 principales son "lenguajes de script" o "dialectos SQL ", donde la" facilidad de uso "y los medios de abstracción tienen mucha más importancia que el comportamiento determinista. Del resto de los idiomas "compilados", hay alrededor del 50% de los idiomas con SBMM y ~ 50% sin ellos. Entonces, cuando saque los lenguajes de scripting de su cálculo, diría que su suposición es incorrecta, entre los lenguajes compilados los que tienen SBMM son tan populares como los que no.


1
¿Cómo es la "facilidad de uso" diferente del determinismo? ¿No debería considerarse un lenguaje determinista más fácil de usar que uno no determinista?
Philipp

2
@Philipp Solo lo que es determinista o no importa realmente. El tiempo de vida de los objetos no importa por sí solo (aunque C ++ y sus amigos vinculan muchas cosas que importan con el tiempo de vida de los objetos, porque pueden). Cuando se libera un objeto inalcanzable no importa porque, por definición, ya no lo está utilizando.

Una cosa más, varios "lenguajes de secuencias de comandos" como Perl y Python también utilizan el recuento de referencias como medio principal para la gestión de la memoria.
Philipp

1
@Philipp Al menos en el mundo de Python, esto se considera un detalle de implementación de CPython, no una propiedad del lenguaje (y prácticamente cualquier otra implementación evita el recuento). Además, argumentaría que el recuento de referencias de captura general sin exclusión con el ciclo de respaldo GC no califica como SBMM o RAII. De hecho, sería difícil encontrar defensores de RAII que consideren que este estilo de administración de memoria sea comparable a RAII (principalmente porque no lo es, los ciclos en cualquier lugar pueden evitar la desasignación rápida en cualquier otro lugar del programa).

3

Una ventaja importante de un sistema GC que nadie ha mencionado todavía es que se garantiza que una referencia en un sistema GC retendrá su identidad mientras exista . Si se llama IDisposable.Dispose(.NET) o AutoCloseable.Close(Java) en un objeto mientras existen copias de la referencia, esas copias continuarán haciendo referencia al mismo objeto. El objeto ya no será útil para nada, pero los intentos de usarlo tendrán un comportamiento predecible controlado por el propio objeto. Por el contrario, en C ++, si el código invoca deleteun objeto y luego intenta usarlo, todo el estado del sistema queda totalmente indefinido.

Otra cosa importante a tener en cuenta es que la administración de memoria basada en el alcance funciona muy bien para objetos con una propiedad claramente definida. Funciona mucho menos bien, y a veces francamente mal, con objetos que no tienen una propiedad definida. En general, los objetos mutables deben tener propietarios, mientras que los objetos inmutables no necesitan, pero hay una arruga: es muy común que el código use una instancia de tipos mutables para contener datos inmutables, asegurando que no se exponga ninguna referencia a código que podría mutar la instancia. En tal escenario, las instancias de la clase mutable pueden compartirse entre múltiples objetos inmutables y, por lo tanto, no tienen una propiedad clara.


44
La propiedad a la que se refiere en la primera mitad es la seguridad de la memoria. Si bien un GC es una forma muy fácil de lograr la seguridad de la memoria, no es necesario: busque en Rust un ejemplo bien hecho.

@delnan: cuando veo rust-lang.org, parece que mi navegador no puede navegar de manera útil desde allí; ¿Dónde debo buscar más información? Mi impresión es que la seguridad de la memoria sin GC impone ciertas restricciones en las estructuras de datos que pueden no encajar bien con todas las cosas que una aplicación podría necesitar hacer, pero estaría feliz de que se demuestre que está equivocado.
supercat

1
No sé de un solo (o incluso un pequeño conjunto de) buenas referencias para esto; mi conocimiento de Rust se ha acumulado durante un año o dos de leer la lista de correo (y todas las cosas vinculadas en los correos electrónicos, incluidos varios tutoriales, publicaciones de blog de diseño de idiomas, problemas de github, ThisWeekInRust y más). Para abordar brevemente su impresión: Sí, cada construcción segura (necesariamente) impone restricciones, pero para prácticamente cualquier fragmento de código seguro de la memoria, existe una construcción segura adecuada o se puede escribir. Los más comunes ya existen en lenguaje y stdlib, todos los demás pueden escribirse en código de usuario.

@delnan: ¿Rust requiere actualizaciones entrelazadas para los contadores de referencia, o tiene algún otro medio para tratar con objetos inmutables (u objetos mutables envueltos inmutablemente) que no tienen una propiedad definida? ¿Rust tiene un concepto de punteros "propietarios" y "no propietarios"? Recuerdo un artículo sobre punteros de "Xonor" que discutía la idea de que los objetos tienen una sola referencia que los "posee", y otras referencias que no; cuando la referencia "propietaria" queda fuera de alcance, todas las referencias no propietarias se convertirían en referencias a objetos muertos y serían identificables como tales ...
supercat

1
No creo que los comentarios de Stack Exchange sean el medio adecuado para dar un recorrido por un idioma. Si todavía está interesado, puede ir directamente a la fuente (#rust IRC, lista de correo de rust-dev, etc.) y / o contactarme con una sala de chat (debería poder crear una).

-2

En primer lugar, es muy importante darse cuenta de que equiparar RAII a SBMM. o incluso a SBRM. Una de las cualidades más esenciales (y menos conocidas o menos apreciadas) de RAII es el hecho de que 'ser un recurso' es una propiedad que NO es transitiva a la composición.

La siguiente publicación de blog discute este aspecto importante de RAII y lo contrasta con la administración de recursos en lenguajes GC que usan GC no determinista.

http://minorfs.wordpress.com/2011/04/29/why-garbage-collection-is-anti-productive/

Es importante tener en cuenta que aunque RAII se usa principalmente en C ++, Python (por fin la versión no basada en VM) tiene destructores y GC determinista que permite que RAII se use junto con GC. Lo mejor de ambos mundos si lo fuera.


1
-1 Ese es uno de los peores artículos que he leído.
Jon Harrop

1
El problema en los idiomas no es que sean compatibles con GC, sino que abandonen RAII. No hay razón para que un lenguaje / marco no pueda soportar ambos.
supercat

1
@ Jon Harrop, ¿podrías dar más detalles? De las afirmaciones hechas en el artículo, ¿hay alguna de las primeras 3 afirmaciones que no se cumple? Creo que puede estar en desacuerdo con el reclamo de productividad, pero los otros 3 reclamos son absolutamente válidos. Lo más importante es el primero sobre la transitividad de ser un recurso.
user1703394

2
@ user1703394: En primer lugar, todo el artículo se basa en un "lenguaje GCed" de paja cuando, de hecho, no tiene nada que ver con la recolección de basura. En segundo lugar, culpa a la recolección de basura cuando, de hecho, las fallas recaen en la programación orientada a objetos. Finalmente, su argumento es 10 años demasiado tarde. La gran mayoría de los programadores ya se modernizaron a los idiomas recolectados de basura precisamente porque ofrecen una productividad mucho mayor.
Jon Harrop

1
Sus ejemplos concretos (RAM, identificadores de archivos abiertos, bloqueos, hilos) son bastante reveladores. Me cuesta recordar la última vez que tuve que escribir código que tratara directamente con cualquiera de esos. Con RAM, el GC automatiza todo. Con los identificadores de archivo, escribo código como File.ReadLines file |> Seq.lengthdonde las abstracciones manejan el cierre para mí. Cerraduras e hilos que he reemplazado con .NET Tasky F # MailboxProcessor. Todo este "explotamos la cantidad de gestión manual de recursos" es un completo disparate.
Jon Harrop
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.