lesson java .net weak-references internals

java - lesson using swing components



¿Cómo se implementan las referencias débiles? (5)

El PEP 205 de Python tiene una explicación decente de cómo deben comportarse las referencias débiles en Python, y esto da una idea de cómo se pueden implementar. Dado que una referencia débil es inmutable, puede tener solo una para cada objeto, a la que le pasa las referencias según sea necesario. Por lo tanto, cuando el objeto se destruye, solo se debe invalidar una referencia débil.

Me pregunto cómo funcionan las referencias débiles internamente, por ejemplo en .NET o en Java. Mis dos ideas generales son:

  1. "Intrusivo": para agregar una lista de referencias débiles a la clase más alta (clase de objeto). Luego, cuando se destruye un objeto, todas las referencias débiles pueden iterarse y establecerse en nulas.
  2. "No intrusivo": para mantener un hashtable de punteros de objetos a listas de referencias débiles. Cuando se crea una referencia débil A para un objeto B, habría una entrada en la tabla hash modificada o creada, cuya clave sería el puntero a B.
  3. "Sucio": para almacenar un valor hash especial con cada objeto, que se pondría a cero cuando se destruya el objeto. Las referencias débiles copiarían ese valor de hash y lo compararían con el valor del objeto para verificar si el objeto está vivo. Sin embargo, esto causaría errores de infracción de acceso, cuando se usara directamente, por lo que tendría que haber un objeto adicional con ese valor hash, creo.

Cualquiera de estas soluciones parece limpia o eficiente. ¿Alguien sabe cómo se hace realmente?


El enfoque normal, creo, es que el sistema mantenga algún tipo de lista de referencias débiles. Cuando se ejecuta el recolector de basura, antes de que se eliminen los objetos muertos, el sistema itera a través de la lista de referencias débiles e invalida cualquier referencia cuyo objetivo no haya sido etiquetado en vivo. Dependiendo del sistema, esto puede ocurrir antes o después de que el sistema resucite temporalmente los objetos elegibles para su finalización inmediata (en el caso de .net, hay dos tipos de WeakReference uno de los cuales se procesa de manera efectiva antes de que el sistema busque los finalizadores). , lo que significa que dejará de ser válido cuando su objetivo sea elegible para su finalización, y uno de los cuales se procesa después.

Incidentalmente, si estuviera diseñando un marco basado en gc, agregaría un par de otros complementos: (1) un medio para declarar una ubicación de almacenamiento de tipo de referencia como una referencia que es principalmente de interés para otra persona, y (2) Una variedad de WeakReference que podría indicar que las únicas referencias a un objeto son "de interés para otra persona" ubicaciones de almacenamiento. Aunque WeakReference es un tipo útil, el acto de convertir una referencia débil en una referencia fuerte puede evitar que el sistema reconozca que a nadie le importaría que su objetivo desapareciera.


No estoy seguro de haber entendido tu pregunta, pero puedes echar un vistazo a la implementación de la clase WeakReference y su superclase Reference en Java. Está bien comentado y puede ver que tiene un campo tratado especialmente por el GC y otro utilizado directamente por la máquina virtual.


Parece que la implementación de referencias débiles es un secreto bien guardado en la industria ;-). Por ejemplo, a partir de ahora, el artículo de wikipedia carece de detalles de implementación. Y mira las respuestas anteriores (incluyendo las aceptadas): "ve a buscar la fuente" o "creo";

De todas las respuestas, solo la que hace referencia al PEP 205 de Python es perspicaz. Como dice, para cualquier objeto individual, puede haber a lo sumo una referencia débil, si tratamos a la referencia débil como una entidad en sí misma.

El resto describe la implementación del lenguaje Squirrel. Por lo tanto, weakref es en sí mismo un objeto, cuando pones una referencia débil a un objeto en algún contenedor, realmente pones una referencia a un objeto weakref. Cada objeto contable de referencia tiene un campo para almacenar el puntero a su referencia débil, que es NULL hasta que se solicita realmente la referencia a ese objeto. Cada objeto tiene un método para solicitar la debilidad de referencia, que devuelve la referencia existente (singleton) debilidad del campo o lo crea y almacena en el campo.

Por supuesto, la referencia débil apunta al objeto original. Entonces, solo necesita ir a través de todos los lugares disponibles donde se manejan las referencias a los objetos y agregar un manejo transparente de las referencias débiles (es decir, eliminarlas automáticamente). (La alternativa "transparente" es agregar el método de "acceso" virtual que será la identidad para la mayoría de los objetos y la falta de referencia real para la referencia débil).

Y como el objeto tiene un puntero a su referencia débil, entonces el objeto puede NULIFICAR la referencia débil en su propio destructor.

Esta implementación es bastante limpia (no hay "llamadas a GC" ni nada mágico) y tiene un costo de tiempo de ejecución O (1). Por supuesto, es bastante codicioso para la memoria: es necesario agregar un campo de puntero de +1 a cada objeto, aunque normalmente para más del 90% de los objetos sería NULL. Por supuesto, los VHLL ya tienen una gran sobrecarga de memoria por objeto, y puede haber posibilidad de compactar diferentes campos "extra". Por ejemplo, el tipo de objeto suele ser una pequeña enumeración, por lo que puede ser posible fusionar el tipo y alguna clase de referencia de referencia débil en una sola palabra de máquina (por ejemplo, mantener los objetos de referencia débil en una arena separada y usar el índice para eso).


En .NET, cuando se crea una WeakReference , al GC se le pide un identificador / identificador opaco que representa la referencia. Luego, cuando sea necesario, WeakReference usa este identificador para preguntar al GC si ese identificador sigue siendo válido (es decir, el objeto original todavía existe), y si es así, puede obtener la referencia real del objeto.

Así que esto es construir una lista de tokens / handle contra direcciones de objetos (y presumiblemente mantener esa lista durante la desfragmentación, etc.)

No estoy seguro de entender al 100% las tres viñetas, por lo que vacilo en adivinar cuál (si existe) es el más cercano.