jak pobierać duże pliki bez problemów z pamięcią w Javie

Kiedy próbuję pobrać duży plik, który ma 260MB z serwera, pojawia się błąd: java.lang.OutOfMemoryError: Java heap space. jestem pewien, że mój rozmiar sterty jest mniejszy niż 252mb. Czy jest jakiś sposób, aby pobrać duże pliki bez zwiększania rozmiaru sterty?

Jak mogę pobrać duże pliki bez tego problemu? Mój kod jest podany poniżej:

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();
Author: kamaci, 2011-08-18

4 answers

Są 2 miejsca, w których widzę, że potencjalnie możesz budować zużycie pamięci:

  1. w buforze odczytu pliku wejściowego.
  2. w buforze zapis do strumienia wyjściowego (HTTPOutputStream?)

Dla #1 sugerowałbym czytanie bezpośrednio z pliku przez FileInputStream Bez BufferedInputStream. Najpierw wypróbuj tę opcję i sprawdź, czy rozwiązuje ona problem. ie:

FileInputStream in = new FileInputStream(file);   

Zamiast:

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

Jeśli #1 nie rozwiąże problemu, możesz spróbować okresowo spłukiwać strumień wyjściowy po zapisaniu tak dużej ilości danych (w razie potrzeby zmniejsz rozmiar kawałka):

Ie:

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();
    }
}
 16
Author: JJ.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-28 14:18:18

Niestety nie wspomniałeś, jaki typ out jest. Jeśli masz problemy z pamięcią, to chyba ByteArrayOutpoutStream. Więc zastąp go przez FileOutputStream i zapisz bajt, który pobierasz bezpośrednio do pliku.

BTW, nie używaj metody read(), która odczytuje bajt po bajcie. Zamiast tego użyj read(byte[] arr). To jest o wiele szybsze.

 4
Author: AlexR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-18 11:41:16

Najpierw możesz usunąć (in != null) z Twojej instrukcji while, jest to niepotrzebne. Po drugie, spróbuj usunąć BufferedInputStream i po prostu zrób:

FileInputStream in = new FileInputStream(file);
 0
Author: Triton Man,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-18 11:52:42

Nie ma nic złego (jeśli chodzi o zużycie pamięci) w wyświetlanym kodzie. Albo kontener serwletów jest skonfigurowany do buforowania całej odpowiedzi (spójrz na konfigurację web.xml), albo pamięć jest wyciekana gdzie indziej.

 0
Author: Michael Borgwardt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-18 12:00:08