Darren Thomas da una buena respuesta. Sin embargo, una gran diferencia entre los enfoques de Java y Python es que con el recuento de referencias en el caso común (sin referencias circulares) los objetos se limpian inmediatamente en lugar de en una fecha posterior indeterminada.
Por ejemplo, puedo escribir código descuidado, no portátil en CPython como
def parse_some_attrs(fname):
return open(fname).read().split("~~~")[2:4]
y el descriptor de archivo para ese archivo abrí será limpiado de inmediato porque tan pronto como la referencia a la intemperie archivo desaparece, el archivo es basura recolectada y el descriptor de archivo se libera. Por supuesto, si ejecuto Jython o IronPython o posiblemente PyPy, el recolector de basura no se ejecutará necesariamente hasta mucho más tarde; posiblemente me quedaré sin descriptores de archivo primero y mi programa se bloqueará.
código por lo que debería estar escribiendo que se parece a
def parse_some_attrs(fname):
with open(fname) as f:
return f.read().split("~~~")[2:4]
pero a veces la gente le gusta depender de recuento de referencias para siempre liberar sus recursos, ya que a veces puede hacer que el código un poco más corto.
Yo diría que el mejor recolector de basura es el que tiene el mejor rendimiento, que actualmente parece ser el basurero generacional al estilo Java que puede ejecutarse en un hilo separado y tiene todas estas optimizaciones locas, etc. las diferencias en la forma de escribir el código deberían ser insignificantes e idealmente inexistentes.
Una diferencia adicional importante es que el GC ansioso mediante recuento de referencias siempre utiliza memoria "mínima" (excepto en el caso de dependencia circular), mientras que el enfoque lento de Java puede hacer que la JVM use mucha más memoria de la que realmente se necesita. GC run lo vuelve a poner en línea. El enfoque de Java da velocidad a costa de la memoria y tiene la ventaja de que la memoria es abundante. Cuando es escaso, el enfoque de Python funcionará mejor. –
El recuento de referencias es más lento que el marcado/barrido GC por un par de otras razones: 1. las escrituras de memoria para actualizar los recuentos de referencia son costosas y causan problemas de concurrencia ya que requieren sincronización. 2. Los recuentos de referencia utilizan memoria extra, lo que aumenta el tamaño del objeto y, por lo tanto, aumenta la presión de la memoria caché. – mikera