Author Topic: Error ClassNotFoundException  (Read 12288 times)

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Error ClassNotFoundException
« on: Octubre 25, 2008, 11:46:20 am »
Hola,

Estoy creando una aplicación en Java la cual uso Java 3D para crear imágenes tridimensionales y demás. Cuando lo ejecuto desde NetBeans en modo depuración me va perfecto, pero el problema es cuando creo el .jar de la aplicación y la ejecuto a partir de ese archivo.

Me salta el siguiente error:

Exception in thread "Thread-1" java.lang.NoClassDefFoundError: javax/media/j3d/G
eometry
        at Hilo1.run(VentanaAplicacion.java:1521)
Caused by: java.lang.ClassNotFoundException: javax.media.j3d.Geometry
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClassInternal(Unknown Source)
        ... 1 more

Este error me aparece cuando le doy a un botón de mi aplicación, el cual crea un nuevo hilo y una instancia de la clase a la que le he dado el nombre "Helicoptero", la cual hace las tareas de creación de la figura en 3D. El error me lo da en la siguiente línea de código:

Code: [Select]
helicoptero = new Helicoptero();
¿Cómo puedo solucionar mi problema y a qué se debe que me aparezca ese error si en teoría está todo correcto? Espero que alguien me pueda echar una mano en el tema.

Muchas gracias desde ya, un saludo.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #1 on: Octubre 25, 2008, 02:46:22 pm »
Hola:

La aplicación no encuentra la clase javax.media.j3d.Geometry. Tienes que distribuir el jar que contenga esa clase junto al tuyo y añadirlo en el CLASSPATH.

Se bueno.

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #2 on: Octubre 25, 2008, 03:25:54 pm »
¿Dónde puedo encontrar el .jar de esa clase que no encuentra? Y una vez que lo tenga.... ¿que lo copio directamente en la carpeta donde tengo los fuentes de la aplicación? Es que de este tema ando algo perdido y no sé muy bien cómo resolverlo.

Por otra parte, lo del classpath, ¿lo tengo que hacer manualmente o lo puedo hacer desde código?. Como he dicho, no entiendo mucho sobre el tema, con lo que necesito que me guiéis para acabar con esto.

Muchas gracias, un saludo.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #3 on: Octubre 25, 2008, 04:11:25 pm »
Hola:

Si has hecho una aplicación con java3d supongo que has bajada o instalado java3d. Esos jars son lo s que tienes que usar.

El classpath puedes fijarlo en el fichero de manifiesto de tu propio jar.

Se bueno.

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #4 on: Octubre 25, 2008, 04:53:27 pm »
Te comento Chuidiang qué es lo que me pasa al realizar lo que me has dicho, a ver si puedo solucionarlo. En mi archivo "manifiest.mf" tengo lo siguiente:

Manifest-Version: 1.0
CLASSPATH: C:\Documents and Settings\sevi\Desktop\Aplicacion\Proyecto
X-COMMENT: Main-Class will be added automatically by build

Lo del classpath lo he metido yo pero no sé si es así realmente o no. Al menos no me ha dado fallo al crear el ".jar". Los ficheros ".jar" de J3D que he metido con el código fuente son:

j3dcore.jar
j3dutils.jar
vecmath.jar

He cogido todos de la carpeta lib de Java 3D. Al ejecutarlo sigue dándome el mismo fallo. ¿A qué se debe este hecho? ¿Qué estoy haciendo mal?

Saludos.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #5 on: Octubre 25, 2008, 05:46:19 pm »
Hola:

Pon lo de Class-Path exactamente como te dice en el enlace que te puse, no puedes inventar las palabras. Los paths a los jar deben ser relativos a la ubicación de tu jar, y no absolutos.

Se bueno.

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #6 on: Octubre 25, 2008, 07:54:01 pm »
Problema resuelto, pero ahora me he encontrado con lo siguiente. Estoy usando la librería gratuita para gráficas JFreeChart, y creo un BufferedImage cada 500 milisegundos. Llega un momento en el que no tiene más memoria en el heap de Java y la aplicación se queda colgada, no me deja tocar los botones, pero las gráficas se siguen viendo y a su velocidad habitual.

Mi pregunta es: ¿cómo puedo hacer para que no tenga ese problema de memoria en mi aplicación? La línea de código que uso para crear la imagen de las gráficas es la siguiente:

image = chart.createBufferedImage(310,296);

Espero que alguien me pueda echar una mano, porque sé que la memoria sobrante la recoge automáticamente el recolector de basura de Java, pero en mi caso no sé cómo solucionar este problema.

Saludos y gracias de antemano.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #7 on: Octubre 25, 2008, 08:33:20 pm »
Hola:

Que no te deje tocar en la aplicación no quiere decir necesariamente que sea un problema de memoria. Quizás estés dejando colgado el hilo de repintado de ventanas.

Si es problema de memoria, te tiene que saltar una excepción de que no hay más espacio en memoria. Si es así, puedes solucionarlo llamando a java de esta manera

java -Xmx1024M

donde 1024M es el número de megas que deseas que tenga la máquina virtual, pon el número que consideres adecuado. Esto, de todas formas, si tu aplicación consume memoria sin liberarla, lo único que hará será retardar la aparición de la excepción.

Si no tienes excepción, posiblemente estás bloqueando el hilo de repintado. Aquí tienes un enlace que te indica cómo debes hacer las cosas para no bloquear el hilo de repintado.

Se bueno.

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #8 on: Octubre 25, 2008, 08:43:23 pm »
Sí que me aparece la excepción, y es lo que tú dices, que tarde o temprano me salta ese error debido a que se consume la memoria. He estado mirando en Internet el uso de las gráficas realizadas mediante JFreeChart, y los ejemplos que he visto solamente crean las gráficas de manera estática, es decir, poniendo:

Code: [Select]
XYSeries serie = new XYSeries();
serie.add(1, 1);
serie.add(2, 2);
....
....
....
....

Y así sucesivamente, creando luego el gráfico de una vez. Yo creo la gráfica dinámicamente, es decir, llamando a la función que contiene el createBufferedImage tantas veces como datos tenga que pintar, y eso pueden ser infinitos, según el usuario desee mostrar. Entonces he pensado en que quizás el problema sea por eso, pero no entiendo cómo puedo resolverlo, debido a que tengo que hacerlo así por requisitos del usuario.

¿Alguien sabe cómo puedo hacer para que no me salte la excepción tarde o temprano y el programa ejecute tanto como el usuario necesite? Es un simulador, con lo que la gráfica debe ser dinámica. Además, el programa a priori no se sabe cuánto tiempo puede estar ejecutando. Todo ello hace que la solución no sea tan obvia como en otras ocasiones.

Espero que alguien me pueda echar una mano. De antemano muchas gracias y un saludo.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #9 on: Octubre 25, 2008, 09:15:58 pm »
Hola:

El ordenador tiene una memoria limitada, así que nunca podrá mostrar infinitos datos a petición del usuario. Tienes que poner un límite.

Fijando el límite, puedes mostrar más gráficos y datos si revisas el programa para hacer un uso más eficiente de la memoria, no repitiendo datos, liberando lo que no necesites, etc.

Si estás usando muchas ventanas, no hagas muchos new JDialog() ni new JFrame() ni del resto de los componentes, trata de reaprovecharlos. Para que las ventanas las recoja el recolector de basura es necesario llamar a su método dispose(). Aun así, es posible que los JFrame no se liberen nunca, por lo que sólo deberías tener como mucho uno, correspondiente a la ventana principal de la aplicación, que teóricamente no debe liberarse hasta que se termina la aplicación.

Se bueno.

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #10 on: Octubre 26, 2008, 10:59:53 am »
Chuidiang en mi caso solamente uso una única ventana para el tema de las gráficas y otra para la visualización de la figura en 3D. El error que me salta es el siguiente:

Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
        at java.awt.image.DataBufferInt.<init>(DataBufferInt.java:41)
        at java.awt.image.Raster.createPackedRaster(Raster.java:458)
        at java.awt.image.DirectColorModel.createCompatibleWritableRaster(DirectColorModel.java:1015)
        at java.awt.image.BufferedImage.<init>(BufferedImage.java:312)
        at org.jfree.chart.JFreeChart.createBufferedImage(JFreeChart.java:1384)
        at org.jfree.chart.JFreeChart.createBufferedImage(JFreeChart.java:1366)

Dentro de esa función a la que llamo varias veces, cada 100 msegundos por ejemplo, tengo el siguiente código:

Code: [Select]
    public BufferedImage creaImagen(int datoMostrar, int tipoGraf, int colHex1, int colHex2)
    {
        double valorMax1 = 0, valorMax2 = 0, valorMin = 0;
       
        if(datoMostrar == 0)
        {
            if(this.reiniciarSim == 1)
            {
                if(tipoGraf == 1)
                {
                    serie1.clear();
                    serie2.clear();
                }
                else
                {
                    serie3.clear();
                    serie4.clear();
                }
            }
           
            //if(CajaX1.isSelected() == true)
                //serie1.add(0, 0);
           
            //if(CajaX2.isSelected() == true)
                //serie2.add(0, 0);
        }
        else
        {
            i = i + 0.1;
           
            if(CajaX1.isSelected() == true && tipoGraf == 1)
            {
                valorMax1 = variables.getRef();
                //System.out.println("Aqui leemos " + valorMax1);
                serie1.add(i, valorMax1);
            }
               
           
            if(CajaX2.isSelected() == true && tipoGraf == 1)
            {
                valorMax2 = variables.getVarContr();
                serie2.add(i, valorMax2);
            }
           
            if(CajaX3.isSelected() == true && tipoGraf == 2)
            {
                valorMax1 = variables.getSeñalControl();
                serie3.add(i, valorMax1);
            }
        }
       
        juegoDatos.removeAllSeries();
       
        if(CajaX1.isSelected() == true && tipoGraf == 1)
            juegoDatos.addSeries(serie1);
       
        if(CajaX2.isSelected() == true && tipoGraf == 1)
            juegoDatos.addSeries(serie2);
       
        if(CajaX3.isSelected() == true && tipoGraf == 2)
            juegoDatos.addSeries(serie3);
       
        /*if(i < 60 && this.time.equals("Min.") == false)
            this.time = "Seg.";
        else
        {
            if(this.limpiar == 1)
            {
                serie1.clear();
                serie2.clear();
                this.limpiar = 0;
            }
           
            this.time = "Min.";
            i = 1;
        }*
       
        String tituloEjeX = new String();
        tituloEjeX = "Tiempo (" + time + ")";*/
       
        if(tipoGraf == 1)
        {
            chart = ChartFactory.createXYLineChart("Referencia y Variable Controlada", "Tiempo (Seg.)","Valor",juegoDatos,PlotOrientation.VERTICAL,true,
            false, true);
            chartAuxiliar = ChartFactory.createXYLineChart("Referencia y Variable Controlada", "Tiempo (Seg.)","Valor",juegoDatos,PlotOrientation.VERTICAL,true,
            false, true);
        }
        else
        {
            chart = ChartFactory.createXYLineChart("Señal de Control", "Tiempo (Seg.)","Valor",juegoDatos,PlotOrientation.VERTICAL,true,
            false, true);
            chartAuxiliar2 = ChartFactory.createXYLineChart("Señal de Control", "Tiempo (Seg.)","Valor",juegoDatos,PlotOrientation.VERTICAL,true,
            false, true);
        }

        plot = chart.getXYPlot();
        rangeAxis = (NumberAxis) plot.getRangeAxis();
       
        if(tipoGraf == 1)
        {
            valorMin = valorMax1;

            if(valorMax1 > valorMax2)
                valorMin = valorMax2;

            if(valorMax1 == 0 && valorMax2 == 0)
                rangeAxis.setRange(0, 10);
            else if(valorMax1 < valorMax2)
                rangeAxis.setRange(valorMin - 20, valorMax2 + 20);
            else if(valorMax1 >= valorMax2)
                rangeAxis.setRange(valorMin - 20, valorMax1 + 20);
        }
        else
            rangeAxis.setRange(valorMax1 - 20, valorMax1 + 20);
       
        domainAxis = (NumberAxis) plot.getDomainAxis();
        if(i <= 10)
            domainAxis.setRange(0, 10);
        else if(i > 10)
            domainAxis.setRange(i - 10, i);
       
        xyplot = chart.getXYPlot();
        xylineandshaperenderer = (XYLineAndShapeRenderer)xyplot.getRenderer();
           
        Color color1 = new Color(colHex1);
        xylineandshaperenderer.setSeriesPaint(0, color1);
        Color color2 = new Color(colHex2);
        xylineandshaperenderer.setSeriesPaint(1, color2);

        image = chart.createBufferedImage(310,296);
        return image;   
    }

Este método se llama por un temporizador, al que le fijo un tiempo entre llamadas según las necesidades del usuario. No sé donde puede estar el problema pero.... el error sigue saliendo. ¿Es posible que haciendo un Thread.sleep() pueda el recolector de basura eliminar de la memoria los elementos no necesarios?

El problema de dormir el hilo es que al tener un temporizador que se llama con una remanencia determinada, eso puede hacer quizás que no funcione adecuadamente y que el Thread.sleep() no sriva de nada, ¿o me equivoco? También he pensando en que cuando vea que la memoria se está acabando, aumentar el tiempo entre llamadas lo bastante como para que la memoria se vacíe lo necesario, ¿o eso no es posible?

Yo de Java entiendo pero no lo suficiente como para saber si eso que comento es correcto, ya que no sé cómo actúa el recolector de basura. Por esta razón os pido ayuda y consejo para poder sacar este tema adelante.

Espero poder solucionar esto hoy porque me es urgente y ¡¡¡¡el cliente quiere el laboratorio para ya!!!!

Un saludo y muchas gracias desde ya ;).

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #11 on: Octubre 26, 2008, 11:50:07 am »
He probado a obtener un dato cada 2 segundos y mostrarlo en la gráfica. El error de memoria em sigue dando, y es curioso, porque me da a partir de los 120 segundos aproximadamente de ejecución. Antes la memoria está más o menos adecuada a lo que estoy ejecutando, pero a partir de los 120 segundos la memoria comienza a decaer hasta que se me queda sin memoria alrededor de los 125 segundos o así.

¿De qué puede ser eso? ¿Puede ser por algo del código que he puesto anteriormente y que haga que en ese momento consuma demasiados recursos del sistema?

Cada vez estoy más perdido en esto, porque solamente me pasa a partir de los 120 segundos más o menos, y no tengo ni idea porqué puede ser el problema. Tengo detectado el error pero no sé cómo solucionarlo. ¿Alguna idea?

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #12 on: Octubre 26, 2008, 12:25:22 pm »
Hola:

Del recolector de basura en principio no tienes que preocuparte, él solo funciona y lo hace bien.

Todas esas imágenes que creas ¿que haces con ellas? ¿Las guardas en algún sitio?.

No sólo no hay que hacer muchos news de JDialog, sino tampoco en general de los JPanel, JButton, etc, etc, etc. Lo normal es construir una única vez la interface de usuario y usarla. Lo digo por si el sitio en el que pintas el BufferedImage estás haciendo un new del componente donde lo pintes y luego lo añades al JDialog.

Si no es nada de esto, lo mejor que uses algún profiler. Son herramientas que te ayudan a ver qué clases estás creando, cuantas hay y en definitiva, por qué se acaba la memoria.

Se bueno.
« Last Edit: Octubre 26, 2008, 12:27:38 pm by chuidiang »

luis

  • Full Member
  • ***
  • Posts: 111
  • Karma: 0
    • View Profile
Re: Error ClassNotFoundException
« Reply #13 on: Octubre 26, 2008, 12:36:45 pm »
A la función creaImagen la llamo desde el método paint(), que cada vez que se ejecuta llama al método indicado de la siguiente manera:

Code: [Select]
this.image=this.creaImagen(0, 2, 0, 0);

En la variable this.image almaceno la gráfica que voy a mostrar. Pues bien, lo único que hago en ese momento es lo siguiente:

Code: [Select]
g.drawImage(this.image,0,325,null);

Siendo "g" la variable de tipo Graphics. Eso es lo único que hago con la imagen, con lo que no sé el porqué del fallo que me da. Quizás con esta parte del código podáis solucionar algo más.

Un saludo.

chuidiang

  • Administrator
  • Hero Member
  • *****
  • Posts: 4985
  • Karma: 12
    • View Profile
    • Apuntes de programación
Re: Error ClassNotFoundException
« Reply #14 on: Octubre 26, 2008, 01:30:26 pm »
Hola:

A los serie.clear() ¿se les llama alguna vez o siempre están añadiendo datos, cada vez que se hace un paint().?  ¿De cuántos datos estamos hablando? ¿No estarás pintando el mismo dato una y otra vez, pero al estar en la misma posición de pantalla no se ve que hay varios?

No parece muy lógico que en cada paint() (java lo llama cada poco), se añadan datos sin borrar los antiguos.

Se bueno.