2011-08-18 38 views
13

Cuando intento descargar un archivo grande que es de 260MB desde el servidor, obtengo este error: java.lang.OutOfMemoryError: Java heap space. Estoy seguro de que mi tamaño de almacenamiento dinámico es inferior a 252MB. ¿Hay alguna forma de que pueda descargar archivos grandes sin aumentar el tamaño del montón?cómo descargar archivos grandes sin problemas de memoria en java

¿Cómo puedo descargar archivos de gran tamaño sin tener este problema? Mi código es el siguiente:

String path= "C:/temp.zip"; 
response.addHeader("Content-Disposition", "attachment; filename=\"test.zip\""); 
byte[] buf = new byte[1024]; 
try { 

      File file = new File(path); 
      long length = file.length(); 
      BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); 
      ServletOutputStream out = response.getOutputStream(); 

      while ((in != null) && ((length = in.read(buf)) != -1)) { 
      out.write(buf, 0, (int) length); 
      } 
      in.close(); 
      out.close(); 
+0

¿Puede aumentar el tamaño del almacenamiento dinámico en la JVM? es decir: java -Xm512m -Xmx512m myClass –

+0

sí, pero me gustaría saber si puedo hacerlo sin aumentar el tamaño del almacenamiento dinámico de jvm, ya que tenemos un requisito para descargar archivos grandes de aproximadamente 1 gb a 10 gb –

Respuesta

16

Hay 2 lugares donde puedo ver que usted podría estar perfilando el uso de memoria:

  1. en el buffer de lectura de su archivo de entrada.
  2. En el almacén de escritura a su flujo de salida (HTTPOutputStream?)

Para # 1 Yo sugeriría leer directamente desde el archivo a través de FileInputStream sin la BufferedInputStream. Pruebe esto primero y vea si resuelve su problema. es decir:

FileInputStream in = new FileInputStream(file); 

en lugar de:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); 

Si # 1 no resuelve el problema, puede probar periódicamente el lavado de la corriente de salida después de tanto los datos se escriben (Disminuir tamaño de la porción, si es necesario):

es decir:

try 
{ 
    FileInputStream fileInputStream = new FileInputStream(file); 
    byte[] buf=new byte[8192]; 
    int bytesread = 0, bytesBuffered = 0; 
    while((bytesread = fileInputStream.read(buf)) > -1) { 
     out.write(buf, 0, bytesread); 
     bytesBuffered += bytesread; 
     if (bytesBuffered > 1024 * 1024) { //flush after 1MB 
      bytesBuffered = 0; 
      out.flush(); 
     } 
    } 
} 
finally { 
    if (out != null) { 
     out.flush(); 
    } 
} 
+1

Gracias JJ esto está trabajando –

+2

Hay un pequeño problema con el código anterior. Necesitamos agregar una descarga más en el bloque finally si se trata de un try-catch que rodea el código o al final del ciclo while. De lo contrario, no vaciará los bytes completos. De lo contrario, puede causar algunos problemas algunas veces. – Arundev

+1

@Arundev: un punto justo, he actualizado el código anterior. –

4

Desafortunadamente usted no ha mencionado qué tipo es out. Si tiene problemas de memoria, supongo que es ByteArrayOutpoutStream. Por lo tanto, reemplácelo por FileOutputStream y escriba el byte que está descargando directamente al archivo.

Por cierto, no use read() método que dice byte a byte. Use read(byte[] arr) en su lugar. Esto es mucho más rápido.

+0

A juzgar por la "respuesta". setContentType "y" response.setHeader "llamadas, esto es un servlet - es decir. está transmitiendo un archivo a un cliente web y "fuera" es el HttpOutputStream. –

+0

gracias alex, pero mi problema principal es descargar archivos más grandes que pueden ser archivos de 1 GB, 10 GB de tamaño. Aquí salgo de la excepción de memoria. ¿Cómo puedo manejar esto sin aumentar el tamaño del montón? –

+0

OK, ahora que ha actualizado su código y la pregunta es mucho más clara. Pensé que su programa está descargando archivos de una URL remota, pero usted está haciendo una pregunta opuesta: su servlet proporciona la capacidad de descargar archivos. Por lo tanto, creo que su problema es que no está llamando.flush() después de cada salida.write(), de modo que todos los bytes que está leyendo se almacenan en la memoria y no se envían a la red hasta que cierre la secuencia de salida. Intenta sonrojar y ver qué está pasando. – AlexR

0

Primero puede eliminar el (en! = Null) de su declaración while, no es necesario. En segundo lugar, intente eliminar el BufferedInputStream y acaba de hacer:

FileInputStream in = new FileInputStream(file); 
0

No hay nada malo (en lo que respecta al uso de la memoria) con el código eres un espectáculo. El contenedor de servlets está configurado para almacenar toda la respuesta (consulte la configuración web.xml), o la memoria se está filtrando en otro lugar.

Cuestiones relacionadas