2010-02-01 10 views
23

No estoy buscando el usual "solo se puede insinuar el GC en Java usando System.gc()" respuestas, de esto no se trata en absoluto de lo que se trata esta pregunta.Java: ¿Cómo fuerza un GC con ForceGargabeCollection de JVMTI?

Mi pregunta no es subjetiva y se basa en una realidad: GC puede forzarse en Java de hecho. Muchos programas que utilizamos diariamente lo hacen: IntelliJ IDEA, NetBeans, VisualVM.

Todos ellos pueden forzar GC para pasar.

¿Cómo se hace?

Supongo que todos están utilizando JVMTI y más específicamente el ForceGarbageCollection (observe la "Fuerza"), pero ¿cómo puedo probarlo por mí mismo?

http://java.sun.com/javase/6/docs/platform/jvmti/jvmti.html#ForceGarbageCollection

También tenga en cuenta que esta cuestión no se trata de "qué" que me gustaría hacer esto: el "por qué" puede ser "curiosidad" o "estamos escribiendo un programa similar al VisualVM", etc.

La pregunta es realmente "¿cómo forzar un GC utilizando ForceGarbageCollection de JVMTI"?

¿La JVM debe iniciarse con algún parámetro especial?

¿Se requiere JNI? Si es así, ¿qué código exactamente?

¿Funciona solo en máquinas virtuales Sun?

Cualquier ejemplo completo y compilable sería muy bienvenido.

Respuesta

10

NetBeans, al menos, usa System.gc(): http://hg.netbeans.org/main/annotate/9779f138a9c9/openide.actions/src/org/openide/actions/GarbageCollectAction.java (esto es para el pequeño botón que muestra el montón actual y le permite iniciar el GC). Si sigues ese enlace, verás que ejecutan explícitamente los finalizadores. Si tiene un poco de espacio en disco libre y desea investigar el código usted mismo, está disponible a través de Mercurial: hg clone http://hg.netbeans.org/main/

Por lo que puedo ver, el "System.gc() es solo una pista" se origina un dogma en una interpretación pedante de las especificaciones JLS y JVM, que permiten implementaciones Java que no tienen un montón recogido de basura. Eso, y una lectura incompleta de la JavaDoc:

Al llamar al método GC sugiere que la Máquina Virtual esfuerzo expend Java hacia el reciclaje de objetos no utilizados en fin de que la memoria que ocupan actualmente disponibles para una rápida reutilización . Cuando el control vuelve de la llamada al método , la Máquina Virtual Java ha hecho un gran esfuerzo para recuperar el espacio de todos los objetos descartados.

Lea la segunda oración: "el mejor esfuerzo para recuperar espacio" es mucho más fuerte que "sugerencia".

Dicho esto, rara vez hay una razón para llamar al System.gc().Con perdón de Knuth:

Debemos olvidarnos de la gestión de memoria, dicen que alrededor del 97% del tiempo: la recolección de basura explícita es la raíz de todo mal

se necesita
+2

Yo no diría que es un dogma basado en una interpretación pedante. La mayoría de las JVM disponibles permiten deshabilitar las llamadas a System.gc(), por lo que no puedes confiar en que hagan nada. Muy a menudo donde tienes una aplicación bien escrita donde el gc funciona bien, presentando una biblioteca donde el desarrollador pensó que podía "asegurarse de que la memoria esté disponible" llamando a System.gc(), apagarla es la mejor manera de obtener respalda tu buen desempeño de gc. – Fredrik

+0

El usuario todavía tiene control sobre eso. Para la VM de hotspot, puede establecer '-XX: + DisableExplicitGC' o no. Por lo tanto, siempre y cuando tenga control sobre las banderas de JVM, 'System.gc()' es bastante confiable. El argumento solo se aplica a los escritores de bibliotecas que no pueden controlar esos indicadores/no pueden suponer en qué máquina virtual se ejecutará. Es un caso general (especificación) contra el uso de hormigón (con todos los parámetros controlados por el usuario). – the8472

+0

Los escritores de aplicaciones generalmente no tienen control de los indicadores de JVM. La excepción es cuando la aplicación está envuelta en un iniciador que evita que el usuario o sysadmin los modifique. Esto no es pedantería. De hecho, la bandera está allí específicamente para proteger a las personas contra las aplicaciones Java/escritores de aplicaciones que hacen cosas estúpidas. –

0
código de la interfaz

Sí JNI para utilizar JVMTI API, ya que es una API nativa. "nativo" significa que solo puede llamarlo directamente desde el código nativo (comprensible c o C++). Entonces, si quiere llamar a esta API desde java, necesita escribir el código JNI para interconectarla.

0

Como ha dicho Anon, tenemos algo similar en eclipse para ejecutar el recolector de basura explícitamente.

Por favor, echar un vistazo a Eclipse: Garbage Collector Button

Esto parece funcionar bastante bien. Le sugiero que eche un vistazo al código que se encuentra detrás de este botón "Ejecutar el recolector de elementos no utilizados" y vuelva a utilizarlo.

Algunos miembros dicen que usa System.gc() pero no puedo confirmarlo. Los expertos de Eclipse pueden arrojar algo de luz aquí.

4

me construyeron un agente de Java básico que permite invocar el JVMTI ForceGarbageCollection función:

#include <stdlib.h> 
#include <stdio.h> 
#include <jvmti.h> 


typedef struct { 
jvmtiEnv *jvmti; 
} GlobalAgentData; 

static GlobalAgentData *gdata; 

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) 
{ 
    printf("load garbager agent\n"); 
    jvmtiEnv *jvmti = NULL; 

    // put a jvmtiEnv instance at jvmti. 
    jint result = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); 
    if (result != JNI_OK) { 
    printf("ERROR: Unable to access JVMTI!\n"); 
    } 

    // store jvmti in a global data 
    gdata = (GlobalAgentData*) malloc(sizeof(GlobalAgentData)); 
    gdata->jvmti = jvmti; 
    return JNI_OK; 
} 


extern "C" 
JNIEXPORT void JNICALL Java_Garbager_forceGarbageCollection(JNIEnv *env, jclass thisClass) 
{ 
    printf("force garbage collection\n"); 
    gdata->jvmti->ForceGarbageCollection(); 
} 

Este agente es llamada a través JNI:

class Garbager { 
    public static void main(String[] args) { 
     Garbager.garbageMemory(); 
    } 

    static void garbageMemory() { 
     forceGarbageCollection(); 
    } 

    private static native void forceGarbageCollection(); 
} 

para compilar el agente en MacOSX:

clang -shared -undefined dynamic_lookup -o garbager-agent.so -I /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/include/ -I /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/include/darwin garbager-agent.cpp 

para lanzar el Garbager:

java -agentpath:garbager-agent.so Garbager 

Sobre la base de este tutorial: Own your heap: Iterate class instances with JVMTI