2008-09-18 14 views
12

¿Alguna vez la máquina virtual Java mueve objetos en la memoria y, de ser así, cómo gestiona la actualización de las referencias al objeto movido?¿Mueve Java VM objetos en la memoria y, de ser así, cómo?

Lo pido porque estoy explorando la idea de almacenar objetos de forma distribuida (es decir, en varios servidores), pero necesito la capacidad de mover objetos entre servidores por razones de eficiencia. Los objetos deben poder contener punteros entre sí, incluso a objetos en servidores remotos. Estoy tratando de pensar en la mejor forma de actualizar las referencias a los objetos movidos.

Mis dos ideas hasta el momento son:

  1. Mantener un direccionamiento indirecto en algún lugar de referencia que no se mueve durante la vida útil del objeto, que actualizamos si el objeto se mueve. Pero, ¿cómo se manejan estas indirecciones?
  2. Mantenga una lista de referencias inversas con cada objeto, para que sepamos qué debe actualizarse si el objeto se mueve. Por supuesto, esto crea una sobrecarga de rendimiento.

Me gustaría recibir comentarios sobre estos enfoques y sugerencias sobre enfoques alternativos.

Respuesta

11

En referencia al comentario anterior sobre caminar el montón.

Diferentes GC lo hacen de diferentes maneras.

Copiando los colectores normalmente cuando caminan por el montón, no caminan todos los objetos en el montón. Más bien caminan los objetos VIVOS en el montón. La implicación es que si es alcanzable desde el objeto "raíz", el objeto está en vivo.

Por lo tanto, en esta etapa tiene que tocar todos los objetos en vivo de todos modos, ya que los copia del antiguo montón al nuevo montón. Una vez que se realiza la copia de los objetos en vivo, todo lo que queda en el antiguo montón son objetos ya copiados o basura. En ese punto, el viejo montón puede descartarse por completo.

Los dos principales beneficios de este tipo de colectores son que compacta el montón durante la fase de copia y que solo copia objetos vivos. Esto es importante para muchos sistemas porque con este tipo de recopilador, la asignación de objetos es muy barata, literalmente poco más que incrementar un puntero de pila. Cuando ocurre GC, ninguno de los objetos "muertos" se copia, por lo que no ralentiza el colector. También resulta en los sistemas dinámicos que hay mucha más basura temporal que cuando hay basura acumulada durante mucho tiempo.

Además, al recorrer el gráfico de objetos en vivo, puede ver cómo el GC puede "conocer" cada objeto y realizar un seguimiento de los mismos para cualquier ajuste de dirección realizado durante la copia.

Este no es el foro para hablar en profundidad sobre la mecánica de GC, ya que es un problema no trivial, pero esa es la base de cómo funciona un recolector de copias.

Copia generacional GC colocará los objetos "antiguos" en diferentes montones, y estos terminan siendo recolectados con menos frecuencia que montones "nuevos". La teoría es que los objetos de larga duración se promueven a generaciones anteriores y se recopilan cada vez menos, lo que mejora el rendimiento general del GC.

3

(Prácticamente) Cualquier sistema de recolección de basura tiene que mover objetos en la memoria para empacarlos de manera más densa y evitar problemas de fragmentación.

Lo que estás viendo es un tema muy grande y complejo. Le sugiero que lea sobre las API de estilo de objetos remotos existentes: .NET remoto y tecnologías más avanzadas como CORBA

Cualquier solución para rastrear las referencias será complicada al tener que lidiar con todos los modos de falla que existen en distribuidos sistemas. La JVM no tiene que preocuparse por encontrar de repente que no puede ver la mitad de su pila porque un conmutador de red falló.

Cuando profundice en el diseño, creo que gran parte se reducirá a la forma en que desea manejar los diferentes casos de falla.

Respuesta a los comentarios:

Su pregunta habla de almacenamiento de objetos de una manera distribuida, que es exactamente lo remoto de .NET y CORBA dirección. Es cierto que ninguna tecnología admite la migración de estos objetos (AFAIK). Pero ambos se ocupan extensamente de los conceptos de identidad de objeto que es una parte crítica de cualquier sistema de objetos distribuidos: cómo las diferentes partes del sistema saben de qué objetos están hablando.

No estoy demasiado familiarizado con los detalles del recolector de basura de Java, y estoy seguro de que los recolectores de basura de Java y .NET tienen mucha complejidad en ellos para lograr el máximo rendimiento con un impacto mínimo en la aplicación.

Sin embargo, la idea básica para la recolección de basura es:

  • La máquina virtual se detiene todos los hilos por debajo código administrado
  • Se realiza un análisis de la accesibilidad del conjunto de 'raíces' conocidos: las variables estáticas, locales variables en todos los hilos. Para cada objeto que encuentra sigue todas las referencias dentro del objeto.
  • Cualquier objeto no identificado por el análisis de accesibilidad es basura.
  • Los objetos que aún están vivos se pueden mover hacia abajo en la memoria para empaquetarlos densamente. Esto significa que cualquier referencia a estos objetos también debe actualizarse con la nueva dirección. Al controlar cuándo puede producirse una recolección de basura, la máquina virtual puede garantizar que no haya referencias de objetos "en el aire" (es decir, que estén retenidos en un registro de máquina) que podrían causar un problema.
  • Una vez que se completa el proceso, la VM inicia los hilos ejecutándose de nuevo.

Como refinamiento de este proceso, la VM puede realizar la recolección de basura generacional, donde se mantienen montones separados según la "antigüedad" de un objeto. Los objetos comienzan en el montón 0 y si sobreviven varios GC, migran al montón 1 y finalmente al montón 2 (y así sucesivamente - .NET solo admite 3 generaciones). La ventaja de esto es que el GC puede ejecutar colecciones de montón 0 con mucha frecuencia, y no tener que preocuparse por hacer el trabajo para probar que los objetos de larga vida (que han terminado en el montón 2) todavía están vivos (lo que casi con seguridad es) .

Existen otros refinamientos para admitir la recolección concurrente de elementos no utilizados, y detalles sobre los hilos que realmente están ejecutando código no administrado cuando el GC está programado, lo que agrega mucha más complejidad a esta área.

+0

Honestamente, no puedo ver la relevancia de .NET remoto y CORBA en esto. ¿Puede proporcionar punteros más específicos? – sanity

+0

Además, realmente lo que estoy buscando es una explicación de * cómo * los sistemas recolectados de basura mueven objetos alrededor. – sanity

+0

@Sanity - Rob Walker recomienda esas tecnologías como un medio para comprender mejor sus estrategias sobre por qué y cómo hacen las cosas que hacen. –

2

La palabra clave que busca es "compactar el recolector de basura". Las JVM tienen permitido usar una, lo que significa que los objetos pueden ser reubicados. Consulte el manual de su JVM para averiguar si lo hace y para ver si hay opciones de línea de comandos que lo afectan.

La forma más simple de explicar la compactación es suponer que el recolector de basura congela todos los hilos, reubica el objeto, busca el montón y la pila para todas las referencias a ese objeto y los actualiza con la nueva dirección. En realidad, es más complejo que eso, ya que por razones de rendimiento no desea realizar un barrido completo con los hilos atascados, por lo que un recolector de basura incremental hará el trabajo de preparación para la compactación siempre que sea posible.

Si le interesan las referencias indirectas, puede comenzar investigando referencias débiles y suaves en Java, y también las referencias remotas utilizadas por varios sistemas RPC.

+0

Interesante, investigaré eso. Pero, ¿no es extremadamente ineficiente buscar en todo el montón las referencias a un objeto? – sanity

+0

Sí y no. En cierto sentido, eso es lo que la fase de "marca" tiene que hacer de todos modos, para averiguar si se hace referencia a un objeto que planea destruir. Así que cientos de años-hombre de trabajo se han dedicado a optimizar los recolectores de basura incrementales, para evitar hacerlo todo de una vez. –

1

suena como si estuvieras buscando un caché distribuido, algo así como terracota u oráculo java objece cache (anteriormente tangersol).

+0

Creo que el producto al que se refiere se llama "Coherencia" y la compañía era Tangosol – Tnilsson

3

Me gustaría saber más acerca de sus requisitos. Como sugiere otra respuesta, Terracotta puede ser exactamente lo que estás buscando.

Sin embargo, existe una sutil diferencia entre lo que proporciona Terracotta y lo que está solicitando, por lo tanto, mi consulta.

La diferencia es que, en lo que a usted respecta, Terracotta no proporciona referencias "remotas" a los objetos; de hecho, la noción "remota" de RMI, JMS, etc. está completamente ausente cuando se utiliza Terracotta.

En cambio, en Terracotta, todos los objetos residen en un gran montón virtual. Los subprocesos, ya sea en el Nodo 1, o el Nodo 2, el Nodo 3, el Nodo 4, etc., todos tienen acceso a cualquier objeto en el montón virtual.

No hay programación especial para aprender, o API especiales, los objetos en el montón "virtual" tienen exactamente el mismo comportamiento que los objetos en el montón local.

En resumen, lo que proporciona Terracotta es un modelo de programación para múltiples JVM que funciona exactamente igual que el modelo de programación para una sola JVM. Los subprocesos en nodos separados simplemente se comportan como subprocesos en un solo nodo: mutaciones de objeto, sincronizadas, espera, notificar que todas se comportan exactamente igual en los nodos que en los subprocesos: no hay diferencia.

Además, a diferencia de cualquier solución que se le presente, las referencias a objetos se mantienen en todos los nodos, lo que significa que puede usar ==. Todo es parte del mantenimiento del Modelo de memoria Java en todo el clúster, que es el requisito fundamental para hacer que el Java "regular" (por ejemplo POJOs, sincronizado, esperar/notificar) funcione (nada de eso funciona si no puede/no puede preservarlo). identidad de objeto en el clúster).

Así que la pregunta vuelve a usted para refinar aún más sus requisitos: ¿para qué necesita punteros "remotos"?

0

Si está dispuesto a profundizar, puede echar un vistazo a los documentos de arquitectura de JBoss Cache y tomar algunos de sus códigos fuente como referencia.

Esto no es exactamente lo que describió, pero funciona muy similar.

Aquí está el enlace.

http://www.jboss.org/jbosscache/

espero que esto ayude.

Cuestiones relacionadas