2008-09-20 20 views
26

(pregunta al estilo Jeopardy, desearía que la respuesta hubiera estado en línea cuando tuve este problema)¿Por qué mi programa Java pierde memoria cuando llamo a ejecutar() en un objeto Thread?

Usando Java 1.4, tengo un método que quiero ejecutar como hilo algunas veces, pero no en otras . Así que lo declare como una subclase de Thread, luego o bien se llama start() o run() según lo que necesite.

Pero encontré que mi programa podría perder memoria con el tiempo. ¿Qué estoy haciendo mal?

Respuesta

45

Se trata de un error conocido en Java 1.4: http://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=5869e03fee226ffffffffc40d4fa881a86e3:WuuT?bug_id=4533087

Se fija en Java 1.5, pero Sun no tiene intención de fijarlo en 1.4.

El problema es que, en tiempo de construcción, se agrega un Thread a una lista de referencias en una tabla de subprocesos internos. No se eliminará de esa lista hasta que se complete su método start(). Mientras esa referencia esté allí, no se recolectará basura.

Por lo tanto, nunca cree un hilo a menos que definitivamente llame al método start(). No se debe llamar directamente al método Thread del objeto run().

Una mejor forma de codificarlo es implementar la interfaz Runnable en lugar de la subclase Thread. Cuando no es necesario un hilo, llame

myRunnable.run(); 

Cuando necesite un hilo:

Thread myThread = new Thread(myRunnable); 
myThread.start(); 
+0

¿Es este un problema que depende de la implementación (por ejemplo, de la JVM de Sun), o está resumido en alguna parte de la Especificación del lenguaje Java? – Alexander

+0

Editado - Investigué un poco más y es un error de JVM – slim

2

Vamos a ver si podíamos conseguir más cerca de la raíz del problema:

Si empiezas tu programa (digamos) 1000 x usando start(), luego 1000 x usando run() en un hilo, ¿ambas memorias se pierden? Si es así, entonces debe verificar su algoritmo (es decir, para objetos externos tales como Vectores utilizados en su Runnable).

Si no hay tal pérdida de memoria como se describe anteriormente, entonces debe investigar acerca de los parámetros de inicio y el uso de la memoria de los hilos con respecto a la JVM.

3

Dudo que al construir una instancia de un subproceso o una subclase del mismo se escape la memoria. En primer lugar, no hay nada de los géneros mencionados en los Javadocs o en la Especificación del lenguaje Java. En segundo lugar, me encontré con una prueba simple y también muestra que no hay memoria se filtró (al menos no en el JDK de Sun 1.5.0_05 de 32-bit x86 Linux 2.6):

public final class Test { 
    public static final void main(String[] params) throws Exception { 
    final Runtime rt = Runtime.getRuntime(); 
    long i = 0; 
    while(true) { 
     new MyThread().run(); 
     i++; 
     if ((i % 100) == 0) { 
     System.out.println((i/100) + ": " + (rt.freeMemory()/1024/1024) + " " + (rt.totalMemory()/1024/1024)); 
     } 
    } 
    } 

    static class MyThread extends Thread { 
    private final byte[] tmp = new byte[10 * 1024 * 1024]; 

    public void run() { 
     System.out.print("."); 
    } 
    } 
} 

EDIT: Sólo para resumir la idea de la prueba anterior. Cada instancia de la subclase MyThread de un subproceso hace referencia a su propia matriz de 10 MB. Si las instancias de MyThread no se recogieron basura, la JVM se quedaría sin memoria muy rápidamente. Sin embargo, ejecutar el código de prueba muestra que la JVM está usando una pequeña cantidad de memoria constante, independientemente del número de MyThreads construidos hasta el momento. Reclamo que esto se debe a que las instancias de MyThread son basura.

+3

Aha - investigué un poco más y descubrí que es un error que se solucionó en Java 1.5 – slim

Cuestiones relacionadas