c# .net garbage-collection weak-references soft-references

¿Las referencias débiles de C#son de hecho suaves?



.net garbage-collection (3)

La diferencia básica es que se supone que se deben reclamar las referencias débiles en cada ejecución del GC (mantener la huella de memoria baja), mientras que las referencias suaves deben mantenerse en la memoria hasta que el GC realmente requiera memoria (intentan ampliar la vida útil pero pueden fallar en cualquier momento). que es útil para, por ejemplo, cachés especialmente de objetos bastante caros).

Que yo sepa, no hay una declaración clara de cómo las referencias débiles influyen en la vida útil de un objeto en .NET. Si son verdaderos refs débiles, no deberían influir en absoluto, pero eso también los haría bastante inútiles para su principal propósito, creo, del almacenamiento en caché (¿estoy equivocado allí?). Por otro lado, si actúan como refs suaves, su nombre es un poco engañoso.

Personalmente, me imagino que se comportan como referencias blandas, pero eso es solo una impresión y no está fundado.

Los detalles de implementación se aplican, por supuesto. Estoy preguntando acerca de la mentalidad asociada con las referencias débiles de .NET: ¿pueden ampliar la vida útil o se comportan como verdaderas referencias débiles?

(A pesar de una serie de preguntas relacionadas, no pude encontrar una respuesta a este problema específico todavía).


¿Las referencias débiles de C # son de hecho suaves?

No.

¿Estoy equivocado allí?

Estás equivocado allí. El propósito de las referencias débiles no es en absoluto el almacenamiento en caché en el sentido que usted quiere decir. Ese es un error común.

¿Son capaces de ampliar la vida útil o se comportan como verdaderos refs débiles?

No, no se expanden de por vida.

Considere el siguiente programa (código F #):

do let x = System.WeakReference(Array.create 0 0) for i=1 to 10000000 do ignore(Array.create 0 0) if x.IsAlive then "alive" else "dead" |> printfn "Weak reference is %s"

Este montón asigna una matriz vacía que es inmediatamente elegible para la recolección de basura. Luego hacemos un bucle de 10M veces asignando más arreglos inalcanzables. Tenga en cuenta que esto no aumenta la presión de la memoria, por lo que no hay ninguna motivación para recopilar la matriz a la que se hace referencia en la referencia débil. Sin embargo, el programa imprime "La referencia débil está muerta" porque se recopiló de todos modos. Este es el comportamiento de una referencia débil. Se habría conservado una referencia suave hasta que su memoria fuera realmente necesaria.

Aquí hay otro programa de prueba (código F #):

open System let isAlive (x: WeakReference) = x.IsAlive do let mutable xs = [] while true do xs <- WeakReference(Array.create 0 0)::List.filter isAlive xs printfn "%d" xs.Length

Esto mantiene filtrando las referencias débiles y colocando una nueva en el frente de una lista vinculada, imprimiendo la longitud de la lista cada vez. En mi máquina, esto nunca supera las 1.000 referencias débiles sobrevivientes. Se incrementa y luego cae a cero en ciclos, presumiblemente porque todas las referencias débiles se recopilan en cada colección gen0. De nuevo, este es el comportamiento de una referencia débil y no una referencia blanda.

Tenga en cuenta que este comportamiento (colección agresiva de objetos con referencias débiles en las colecciones gen0) es precisamente lo que hace que las referencias débiles sean una mala elección para los cachés. Si intentas usar referencias débiles en tu caché, verás que tu caché se está vaciando mucho sin ninguna razón.


No he visto ninguna información que indique que aumentarían la vida útil del objeto al que apuntan. Y los artículos que leí sobre el algoritmo que usa el GC para determinar la accesibilidad tampoco los mencionan de esta manera. Así que espero que no tengan influencia en la vida útil del objeto.

Débiles
Este tipo de identificador se utiliza para rastrear un objeto, pero permite que se recopile. Cuando se recolecta un objeto, el contenido del GCHandle se pone a cero. Las referencias débiles se ponen a cero antes de que se ejecute el finalizador, por lo que incluso si el finalizador resucita el objeto, la referencia débil todavía se pone a cero.

WeakTrackResurrection
Este tipo de identificador es similar a Débil, pero el identificador no se pone a cero si el objeto resucita durante la finalización.

http://msdn.microsoft.com/en-us/library/83y4ak54.aspx

Hay algunos mecanismos por los cuales un objeto que es inalcanzable puede sobrevivir a una recolección de basura.

  • La generación del objeto es más grande que la generación del GC que sucedió. Esto es particularmente interesante para los objetos grandes, que se asignan en el montón de objetos grandes y siempre se consideran Gen2 para este propósito.
  • Los objetos con un finalizador y todos los objetos accesibles desde ellos sobreviven al GC.
  • Puede haber un mecanismo en el que las referencias anteriores de objetos antiguos puedan mantener vivos los objetos jóvenes, pero no estoy seguro de eso.


Las referencias débiles no prolongan la vida útil de un objeto, lo que permite que se recoja la basura una vez que todas las referencias sólidas hayan quedado fuera del alcance. Pueden ser útiles para aferrar objetos grandes que son costosos de inicializar, pero deberían estar disponibles para la colección de garabage si no están en uso.