2009-10-17 13 views
37

¿Qué es lo que determina cuándo se recoge realmente el recolector de basura? ¿Sucede después de un cierto tiempo o después de que se haya agotado una cierta cantidad de memoria? ¿O hay otros factores?Java basurero - ¿Cuándo se acumula?

Respuesta

24

Se ejecuta cuando determina que es hora de ejecutar. Una estrategia común en recolectores de basura generacionales es ejecutar el recopilador cuando falla una asignación de memoria de generación-0. Es decir, cada vez que asigna un pequeño bloque de memoria (los bloques grandes normalmente se colocan directamente en generaciones "anteriores"), el sistema verifica si hay suficiente espacio libre en el montón gen-0, y si no hay, se ejecuta el CG para liberar espacio para que la asignación tenga éxito. Los datos antiguos se mueven al gen-1 y, cuando se agota el espacio, el GC ejecuta una recopilación sobre eso, actualizando los datos que han estado más tiempo en el gen-2 y así sucesivamente. Entonces el GC no solo "corre". Puede ejecutarse solamente en el gen-0 heap (y la mayoría de las colecciones lo harán), o podría verificar cada generación si realmente tiene que liberar mucha memoria (lo cual solo es necesario con bastante poca frecuencia).

Pero esto está lejos de la única estrategia. Un GC simultáneo se ejecuta en segundo plano, limpiando mientras el programa se está ejecutando. Algunos GC pueden ejecutarse como parte de cada asignación de memoria. Un recolector incremental podría hacer eso, escaneando algunos objetos en cada asignación de memoria.

Todo el punto en un recolector de basura es que debería hacer lo suyo sin requerir ninguna entrada del usuario. Entonces, en general, no puedes, y no debes, predecir cuándo se ejecutará.

Creo que Suns JVM ganó un GC generacional no hace mucho tiempo (v1.6 tal vez? No he codificado Java por eras, así que no estoy seguro de esto, pero recuerdo haberme sorprendido no hace mucho tiempo, cuando de los puntos de venta para la nueva versión fue "un GC generacional". No menos importante porque .NET ha tenido uno desde el día 1.)

Otras JVM son, por supuesto, libres de elegir la estrategia que deseen.

EDITAR: La parte anterior sobre Java y generational GC no es verdadera. Consulte a continuación para obtener más detalles:

Las máquinas virtuales 1.0 y 1.1 usaban un colector de barrido de marca, que podía fragmentar el montón después de una recolección de basura. A partir de Java 1.2, las máquinas virtuales cambiaron a un colector generacional, que tiene un comportamiento de desfragmentación mucho mejor (ver Java theory and practice: Garbage collection and performance).

Por lo tanto, Java tiene en realidad un GC generacional por edades. Lo nuevo en Java 6 es el recolector de basura Garbage-First (G1) que está disponible en Java 6u14. De acuerdo con the article claiming the release in 1.6.0_14: No está habilitado por defecto. El colector paralelo sigue siendo el GC predeterminado y es el GC más eficiente para el uso doméstico común. G1 está destinado a ser una alternativa para el colector simultáneo. Está diseñado para ser más predecible y permitir una asignación rápida con diseño de regiones de memoria.

+0

Java tiene un GC generacional desde JDK 1.3 (ver, por ejemplo, aquí: http://www.javaworld.com/javaworld/jw-01-2002/jw-0111-hotspotgc.html) –

+1

@Johannes Weiß No, es desde JDK 1.2 . Las máquinas virtuales 1.0 y 1.1 utilizaban un recopilador de barrido de marca, que podía fragmentar el montón después de una recolección de basura. A partir de Java 1.2, las máquinas virtuales cambiaron a un colector generacional, que tiene un comportamiento de desfragmentación mucho mejor. Ver http://www.ibm.com/developerworks/library/j-jtp01274.html. –

+0

@Pascal Thivent: Ok, el artículo al que me vinculé dijo que JDK1.2 tenía un "recolector de basura exacto" que fue optimizado y renombrado como "GC generacional" en JDK 1.3 pero puede que tenga razón ... –

5

Depende mucho de qué recolector de basura está usando en realidad, cómo está afinado, y una gran cantidad de entradas.

Para un funcionamiento abajo del colector de basura HotSpot (el común que viene con Java) y cómo está sintonizado, se puede extraer this link

+0

parece interesante, lo leerá más adelante. :) – nalo

6
  • Depende de JIT programa de forma compilada.
  • Desde fuera, definitivamente no podemos decir cuándo se ejecutará.
  • Sigue algún algoritmo que depende de ese GC en particular.
  • La máquina virtual de Java se ejecuta en la máquina del cliente con algo de memoria virtual en caso de que el valor predeterminado de Windows sea de 4 GB. También depende de esa memoria virtual gratuita en ese momento particular.

Puede probar este pequeño programa para comprobar el comportamiento de GC

public class GCTest { 

    final int NELEMS = 50000; 

    void eatMemory() { 

     int[] intArray = new int[NELEMS]; 

     for (int i=0; i<NELEMS; i++) { 
     intArray[i] = i; 
     } 

    } 

    public static void main (String[] args) { 

     GCTest gct = new GCTest(); 

     // Step 1: get a Runtime object 
     Runtime r = Runtime.getRuntime(); 

     // Step 2: determine the current amount of free memory 
     long freeMem = r.freeMemory(); 
     System.out.println("free memory before creating array: " + freeMem); 

     // Step 3: consume some memory 
     gct.eatMemory(); 

     // Step 4: determine amount of memory left after consumption 
     freeMem = r.freeMemory(); 
     System.out.println("free memory after creating array: " + freeMem); 

     // Step 5: run the garbage collector, then check freeMemory 
     r.gc(); 
     freeMem = r.freeMemory(); 
     System.out.println("free memory after running gc(): " + freeMem); 
    } 
} 

salida posible - puede ser diferente en su caso

free memory before creating array: 4054912 
free memory after creating array: 3852496 
free memory after running gc(): 4064184 

Comprobar este enlace http://www.devdaily.com/java/edu/pj/pj010008/

1

El El recolector de basura se ejecuta cuando necesita recursos y de manera regular que usted puede influir diciéndole cuándo es un buen momento e para pasar de la CPU en la recopilación, el uso de System.gc()

Puede ayudar al recolector de basura por anulando referencias explícitamente, por ejemplo, dando a sus objetos init() métodos que asignan recursos y métodos que limpian cleanup() explícitamente esos recursos y anulando sus referencias. Al anular las referencias usted mismo, evita que el recolector de basura tye tenga que buscar grupos de obects que tienen más rutas a una raíz.

+0

Para un gc moderno, establecer las variables a nulo o no hará ninguna diferencia y llamar a System.gc() es casi siempre simplemente estúpido. – Fredrik

+2

@Fredrik, no use términos como "estúpido". Establecer variables en nulo es una buena práctica y ayuda a que la recolección de basura se ejecute en pequeños pasos en lugar de fragmentos más grandes. (Tenga en cuenta que hablo de atributos de clase, no de variables de método temporales en la pila). En cuanto a llamar a System.gc(), las aplicaciones triviales no necesitan preocuparse por ello, pero las aplicaciones grandes que obtienen solicitudes simultáneas masivas a veces lo necesitan para mantener el tiempo de recopilación la aplicación receptiva en todo momento. – rsp

+0

@rsp: la forma en que funcionan los GC es casi siempre estúpido o al menos dañino para el rendimiento de gc llamar a System.gc() y no ayuda en absoluto por lo que a) no es obligatorio que el GC siquiera moleste b) es posible desactivarlo para que no sea afectado por un código escrito por alguien que piense que es más inteligente que el algoritmo gc. La razón por la que todavía es posible es porque es como dije "casi siempre" estúpido, lo que significa que hay algunos lugares donde realmente podría querer hacerlo. Establecer las variables en nulo no le da más que más código, no afectará en absoluto al gc. – Fredrik

2

Esto depende completamente de la JVM real y de lo que elija hacer, y básicamente está fuera de sus manos como programador. Expertos recalcitrantes de color gris pueden querer decirle a la JVM que lo saben mejor, pero para los simples mortales esto debería considerarse magia negra, mejor dejarlo solo.

Lo que debería preocuparle es si puede mantener el ritmo que sus programas crean y descarta objetos. Si no, su programa entero se detiene mientras se realiza una limpieza global. Eso resulta en tiempos de respuesta muy malos, pero rara vez ocurre en las JVM modernas en las computadoras modernas.

Si tiene curiosidad sobre lo que sucede en su programa y cuándo, investigue la herramienta "jvisualvm" en las versiones recientes de Java 6 JDK. Es realmente genial para mirar por dentro.

0

Cuando JVM no tiene espacio de memoria necesario para ejecutarse, el recolector de elementos no utilizados ejecutará y eliminará objetos innecesarios y asignará memoria para JVM.

Los objetos innecesarios son los objetos que no tienen ninguna referencia (dirección) para ello.

Hay principalmente 4 puntos para los objetos elegibles para el recolector de basura.

  1. nulo Referencing

    colector

    basura puede eliminar un objeto cuando la variable de referencia del objeto se le asigna nula, ya que es el valor

    A a = new A(); 
        a = null; 
    
  2. Reasignación de

    Cuando otro objeto se asigna a la variable de referencia de un objeto , el objeto referenciado más antiguo se puede eliminar Ted por basura colector.

    A a = new A(100); 
        a =new A(200); 
    
  3. Ámbito Local

    Si se crea un objeto dentro de un bloque de ese objeto es elegible para recolector de basura fuera del lado de ese bloque.

    if(condition){ 
    
        A a = new A(); 
    
        } 
    
  4. Aislamiento

    Un objeto puede referirse otro objeto pero debe haber al menos una (dirección) variable de de referencia para estos objetos en la pila, de lo contrario todos esos objetos son elegibles para el colector de basura.

     class A{ 
          A r; 
          A(int i){ 
          //something 
          } 
         } 
    
         A a1 = new A(100); 
         a1.r = new A(101); 
         a1.r.r = new A(102); 
         a1.r.r.r = a1; 
    
         a1 = null //all ojects are eligible to garbage collector