2009-08-09 12 views
44

¿Alguien ha investigado los costos de tiempo de ejecución involucrados en la creación y recolección de objetos Java WeakReference? ¿Hay algún problema de rendimiento (por ejemplo, contención) para las aplicaciones de subprocesos múltiples?Costo de usar referencias débiles en Java

EDITAR: Obviamente, la (s) respuesta (s) real (es) dependerán de la JVM, pero también son bienvenidas las observaciones generales.

EDIT 2: Si alguien ha hecho alguna evaluación comparativa del rendimiento, o puede señalar algunos resultados de evaluación comparativa, eso sería ideal. (Lo siento, pero la recompensa ha expirado ...)

+0

Obviamente, esto dependerá de la implementación de JDK, Sun vs IBM contra JRockit, etc. –

+4

Inicio de una respuesta en un artículo de [Goetz] (http://www.ibm.com/developerworks/java/library/j- jtp01246/index.html): * En cada recolección de elementos no utilizados, se debe construir una lista de objetos de referencia activos, y cada referencia debe procesarse adecuadamente, lo que agrega cierta sobrecarga por referencia a cada colección independientemente de si el referente se recopila en ese momento. Los propios objetos de referencia están sujetos a la recolección de basura y pueden recopilarse antes que el referente, en cuyo caso no se ponen en cola. * – assylias

Respuesta

12

WeakReferences tienen un impacto negativo en el recolector de basura CMS. Por lo que puedo ver por el comportamiento de nuestro servidor, influye en el tiempo de fase de observación paralela. Durante esta fase, todos los hilos de la aplicación se detienen, por lo que es algo extremadamente indeseable. Por lo tanto, debe tener cuidado con WeakReferences.

+0

Disculpa, pero estoy tratando de descubrir las razones de tal comportamiento en los foros de Sun ahora :) – Vitaly

+2

Vitaly, ¿tienes más en esto ahora? Si encuentra información en los foros de Sun, ¿podría publicar un enlace? ¡Gracias! – Owen

+0

Qué tipo de impacto tienen, obviamente hay un costo, ya que gc necesita referencias especiales de casos débiles, etc. –

3

memoria caché con referencias débiles puede ralentizar significativamente su aplicación si se reconstruye según demanda, p. en captadores:

public Object getSomethingExpensiveToFind() { 
    if(cache.contains(EXPENSIVE_OBJ_KEY)) { 
     return cache.get(EXPENSIVE_OBJ_KEY); 
    } 

    Object sth = obtainSomethingExpensiveToFind(); // computationally expensive 
    cache.put(EXPENSIVE_OBJ_KEY, sth); 
    return sth; 
} 

imaginar este escenario:

1) aplicación se está ejecutando bajo en memoria

2) GC limpia referencias débiles, por lo tanto caché se limpia demasiado

3) aplicación continúa , se invoca una gran cantidad de métodos como getSomethingExpensiveToFind() y reconstruye el caché

4) la aplicación se está quedando sin memoria

5) GC limpia usar referencias, se borra la memoria caché

6) aplicación continúa, una gran cantidad de métodos como getSomethingExpensiveToFind() se invocan y reconstruir la caché de nuevo

7) y así sucesivamente ...

Me encontré con ese problema: la aplicación fue interrumpida por GC muy a menudo y derrotó todo el proceso de almacenamiento en caché.

En otras palabras, si se gestiona incorrectamente, las referencias débiles pueden ralentizar su aplicación.

+1

Esto no responde la pregunta que hice. Básicamente estás diciendo que el uso imprudente de referencias débiles puede ser malo para el rendimiento ... debido a la caché del objeto. Pero la pregunta es sobre los gastos generales de las propias referencias débiles. (Idealmente, me gustaría obtener una respuesta que proporcione algunas medidas reales para esos gastos generales, pero también me conformaría con una explicación * autoritativa * de cómo se incurren.) –

+0

, entonces debería haber preguntado acerca de * indicadores * y * puntos de referencia * Específicamente – mantrid

+0

Lo hice. En el aviso de bonificación. ¿Lo leíste? Pero de todos modos, su respuesta claramente no es relevante para la pregunta como se le preguntó. –

4

Implementé un recolector de basura de Java una vez, así que todo lo que pude lograr es un límite (débil :) más bajo en lo que es posible.

En mi implementación, hay una pequeña cantidad constante de sobrecarga adicional para cada referencia débil cuando se visita durante la recolección de basura.

Así que el resultado es: No me preocuparía, no es un gran problema a menos que esté usando billones de referencias débiles.

Lo que es más importante, el costo es proporcional al número de referencias débiles existentes, no al tamaño del montón global.

Sin embargo, eso no quiere decir que un recolector de basura que admita referencias débiles sea tan rápido como uno que no lo haga. La pregunta que se presume aquí es que, dado que Java admite referencias débiles, ¿cuál es el costo incremental de usarlas?

La mina era un simple "parar el mundo" marca/barre el recolector de basura.Durante la recolección de basura, realiza una determinación para cada objeto, ya sea que ese objeto esté vivo o no, y establece un bit LIVE en el encabezado del objeto. Luego pasa y libera todos los objetos no vivos.

Para manejar referencias débiles que acaba de añadir lo siguiente:

  • Ignorar referencias débiles al establecer LIVE bits (es decir, que no causan el bit LIVE en el objeto referenciado a ajustar).
  • Durante el paso de barrido, agregue un control especial de la siguiente manera: si el objeto que está visitando es LIVE, y es WeakReference, luego verifique el objeto al que hace referencia débilmente, y si ese objeto no es LIVE, borre la referencia .

Pequeñas variaciones de esta lógica funcionan para referencias blandos y fantasmas.

Implementación es here si eres realmente curioso.

+0

Esto es muy interesante. (Creo que la implementación de HotSpot es diferente). ¿Cómo se maneja el caso en el que un método de finalización vuelve a vincular el objeto al que se hace referencia? ¿No necesitaría eso activar una marca (parcial)? –

+0

Estoy 100% seguro de que la implementación de HotSpot no solo es diferente sino mucho más sofisticada :) Re: finalize, eso es solo un paso adicional para objetos que no son LIVE. En lugar de "pasa y libera todos los objetos no vivos" realmente debería decir "pasa y pone en cola para la finalización de todos los objetos no vivos". – Archie

+0

Re: finalización, debe establecer un bit en el encabezado del objeto que indica si 'finalize()' ha sido invocado o no, por lo que no lo hace dos veces según sea necesario. Por lo tanto, en realidad, el objeto que no está '' EN VIVO '' se pone en cola para su finalización si el bit no se establece, o se libera inmediatamente si se establece el bit. – Archie

Cuestiones relacionadas