Foros del Web » Programación para mayores de 30 ;) » Java »

Sockets con ficheros grandes --> OutOfMemoryError

Estas en el tema de Sockets con ficheros grandes --> OutOfMemoryError en el foro de Java en Foros del Web. Hola Estoy haciendo una aplicación cliente-servidor donde el cliente pide un fichero y el servidor lo envía, pero esos ficheros pueden llegar a pesar 1 ...
  #1 (permalink)  
Antiguo 12/03/2010, 18:02
 
Fecha de Ingreso: febrero-2005
Mensajes: 40
Antigüedad: 14 años, 7 meses
Puntos: 2
Sockets con ficheros grandes --> OutOfMemoryError

Hola

Estoy haciendo una aplicación cliente-servidor donde el cliente pide un fichero y el servidor lo envía, pero esos ficheros pueden llegar a pesar 1 o 2 GB.

El caso es que he probado con un fichero de menos de 600MB y cuando el cliente ya ha recibido 61MB el servidor da una excepción de OutOfMemoryError.

A ver si me podéis echar una mano, dejo parte del código con el que estoy probando:

Cliente:
Código:
public void pedir(String fichero) {
        try {
            // Crea la petición y la envía
            MensajeDameFichero mensaje = new MensajeDameFichero();
            mensaje.nombreFichero = fichero;
            out.writeObject(mensaje);
            /* Crea un stream de fichero donde almacenará los bytes que va recibiendo
            y consituirán el fichero recibido */
            ficheroRecibido = new FileOutputStream("a/"+mensaje.nombreFichero + EXTENSION);
            // Comienza a leer los bytes recibidos
            ObjectInputStream in = new ObjectInputStream(cliente.getInputStream());
            MensajeTomaFichero mensajeRecibido;
            Object mensajeAux;
            do {
                mensajeAux = in.readObject();
                if (mensajeAux instanceof MensajeTomaFichero) {
                    mensajeRecibido = (MensajeTomaFichero) mensajeAux;
                    ficheroRecibido.write(mensajeRecibido.contenidoFichero, 0, mensajeRecibido.bytesValidos);
                } else {
                    JOptionPane.showMessageDialog(null, "Error: Mensaje inesperado.", "Error", JOptionPane.ERROR_MESSAGE);
                    break;
                }
            } while (!mensajeRecibido.ultimoMensaje);
            in.close();
            close();
Servidor:
Código:
public void enviar(String fichero, ObjectOutputStream out) {
        try {
            boolean enviadoUltimo = false;
            // abre el fichero a enviar y configura las opciones de envío
            FileInputStream ficheroEnviar = new FileInputStream(fichero);
            MensajeTomaFichero mensaje = new MensajeTomaFichero();
            mensaje.nombreFichero = fichero;
            // empieza a leer y enviar el fichero
            System.out.println("Enviando "+fichero);
            int leidos = ficheroEnviar.read(mensaje.contenidoFichero);
            while (leidos > -1) {
                mensaje.bytesValidos = leidos;
                if (leidos < MensajeTomaFichero.LONGITUD_MAXIMA) {
                    mensaje.ultimoMensaje = true;
                    enviadoUltimo = true;
                } else {
                    mensaje.ultimoMensaje = false;
                }
                out.writeObject(mensaje);

                if (mensaje.ultimoMensaje) break;
                // Nuevo mensaje
                mensaje = new MensajeTomaFichero();
                mensaje.nombreFichero = fichero;
                leidos = ficheroEnviar.read(mensaje.contenidoFichero);
            }
            // si ha quedado el último paquete colgando --> lo envias
            if (!enviadoUltimo) {
                mensaje.ultimoMensaje = true;
                mensaje.bytesValidos = 0;
                out.writeObject(mensaje);
            }
            out.close();
            System.out.println("Enviado "+fichero);
        } catch (FileNotFoundException ex) {
            System.err.println("El fichero solicitado no existe.");
        } catch (IOException ex) {
            System.err.println("Excepción inesperada.\n"+ex);
        }
    }

He leído en la API que para ficheros mayores a 64K hay que indicar a ambos sockets (socket y serversocket) un tamaño mayor con setReceiveBufferSize(<tamaño>) para que cree los buffers del tamaño adecuado, pero aun indicándole un tamaño de 700MB (mi fichero es de menos de 600MB) sigue saltando la misma excepción.


Muchas gracias por adelantado.
  #2 (permalink)  
Antiguo 12/03/2010, 18:24
Avatar de pablor21  
Fecha de Ingreso: noviembre-2008
Ubicación: Montevideo - Uruguay
Mensajes: 197
Antigüedad: 10 años, 11 meses
Puntos: 13
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

Hola!
Seguramente lo que está pasando es que la jvm es la que no soporta la carga de memoria, utiliza los siguientes parámetros en la llamada a tu programa, y fíjate si soluciona tu problema
-Xms < tamaño > para el tamaño inicial de memoria
-Xmx < tamaño > para el tamaño maximo de memoria

por ejemplo

java -Xmx700m miprograma

__________________
Desarrolloador Freelance - http://www.mvdit.com.uy
  #3 (permalink)  
Antiguo 12/03/2010, 18:51
 
Fecha de Ingreso: febrero-2005
Mensajes: 40
Antigüedad: 14 años, 7 meses
Puntos: 2
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

Ok, muchas gracias ^^

Ahora solo queda un problema de concepto y de cómo podría hacerlo sin incrementar la memoria de la JVM ya que, en principio, debería ir liberando de la memoria lo que va escribiendo en disco... no? :S


Muchas gracias de nuevo ^^
  #4 (permalink)  
Antiguo 12/03/2010, 18:59
Avatar de pablor21  
Fecha de Ingreso: noviembre-2008
Ubicación: Montevideo - Uruguay
Mensajes: 197
Antigüedad: 10 años, 11 meses
Puntos: 13
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

quizás lo mejor es que no mandes el fichero todo de una, o sea, que envíes una parte, guardes un marcador de los bytes enviados, llamar al gc (que no garantiza que se ejecute inmediatamente) y sigas enviando otra parte, o quizás poniendo el envío de fichero dentro de un hilo, y pausándolo para darle un respiro a la jvm... pero la verdad no estoy demasiado seguro que sea una solución, creo que lo mejor es que pruebes y nos cuentes...
Si tienes alguna duda sobre cómo hacer algo de esto me preguntas

__________________
Desarrolloador Freelance - http://www.mvdit.com.uy
  #5 (permalink)  
Antiguo 13/03/2010, 00:42
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 16 años
Puntos: 51
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

Si estas enviando ficheros de ese tamaño y lo que envias son bytes, es una barbaridad usar Object(Input/Output)Stream ya que eso obliga a que el objeto enviado/recibido esté de golpe todo en memoria, así que con ficheros 1/2 Gbde no te cabrá en ninguna máquina de 32bits, suponiendo que sólo tuvieras el programa en memoria.

Lo que tienes que hacer es ir leyendo el fichero con un InputStream "simple" (un BufferedInputStream por ejemplo) y lo que lees de disco, directamente enviarlo. Y al recibirlo, igual, lo lees lo escribes directamente a disco con un simple BufferedOuputStream.

De esta forma, nunca necesitarás tener todo el fichero a la vez en memoria y por tanto tu programa no necesitará que le quepa entero en la JVM.

S!
__________________
Para obtener respuestas, pregunta de forma inteligente o si no, pregunta lo que quieras que yo contestaré lo que me dé la gana.
  #6 (permalink)  
Antiguo 14/03/2010, 14:11
 
Fecha de Ingreso: febrero-2005
Mensajes: 40
Antigüedad: 14 años, 7 meses
Puntos: 2
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

Cita:
Iniciado por GreenEyed Ver Mensaje
Si estas enviando ficheros de ese tamaño y lo que envias son bytes, es una barbaridad usar Object(Input/Output)Stream ya que eso obliga a que el objeto enviado/recibido esté de golpe todo en memoria
Ups, desconocía esto, pensaba que los objetos que enviaba y recibía se iban liberando.

Intentaré reconstruir la aplicación con los Buffered tal como indicas y ya comentaré ^^

Un saludo y muchas gracias de nuevo
  #7 (permalink)  
Antiguo 14/03/2010, 15:00
 
Fecha de Ingreso: octubre-2003
Mensajes: 3.578
Antigüedad: 16 años
Puntos: 51
Respuesta: Sockets con ficheros grandes --> OutOfMemoryError

Cita:
Iniciado por MIRL27 Ver Mensaje
Ups, desconocía esto, pensaba que los objetos que enviaba y recibía se iban liberando.
Si lo vas haciendo a base de multiples objetos, puede, si los liberas bien, pero aun así, internamente los objectXstream mantienen referencias a los objetos que han manejado para poder saber si otro objeto de la misma clase que viene/va es uno que ya han tratado o no, así que seguramente debido a esas referencias internas no se libere todo.

De todas formas, si lo que te interesa que llegue al otro lado son los bytes, con ficheros tan grandes lo mejor es enviarlo al nivel mas bajo posible para consumir menos.

Suerte y ya nos dirás que tal.

S!
__________________
Para obtener respuestas, pregunta de forma inteligente o si no, pregunta lo que quieras que yo contestaré lo que me dé la gana.

Etiquetas: ficheros, grandes, sockets
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 21:56.