download pliku, Out Of Memory

0

Witam,
jestem w trakcie tworzenia aplikacji webowej z wykorzystaniem Springa i JSF. Zaimplementowałem upload pliku za pomocą biblioteki MyFaces Tomahawk i t:inputFileUpload. Wszystko działa ok. Mam natomiast problem z downloadem pliku, zwłaszcza dużego - w bazie trzymane są tylko ścieżki do plików. Napisałem servlet wg wzoru, których jest dużo na różnych stronach, główna jego część:

 
File file = new File(path);
FileInputStream in = new FileInputStream(file);
ServletOutputStream out = response.getOutputStream();
response.setHeader("Content-Disposition","attachment; filename=\"" + filename +"\" ");
response.setHeader("Content-Type", "application/pdf");   // download dotyczy plików pdf
response.setHeader("Content-Length", String.valueOf(file.length()));
int bytesRead = -1;  
byte[] buffer = new byte[4096];  
while((bytesRead = in.read(buffer)) != -1)  {  
    out.write(buffer, 0, bytesRead);  
}   
out.flush();  
in.close();  
out.close(); 

Po deployu na serwer, download działa, ale bardzo rośnie stos i po kilku downloadach wyrzuca Out Of Memory. Początkową wielkość sterty mam ustawioną na 512MB, max na 1024MB. Plik po prostu jest trzymany w pamięci. Użyłem narzędzia JProfiler, które potwierdziło, że problem jest z downloadem. Zaalokowane było 650MB dla byte[]. Jak uruchomił się GC, to wielkosc stosu trochu spadała. Ma może ktoś sposób jak rozwiązać download pliku? Jak zacznie pobieranie kilka osób, to Out Of Memory gwarantowany!

0

Obecnie piszesz na OutputStream i dopiero po zakończeniu pisania wywołujesz flush(). Zwiększ wielkość bufora do np. 512kb i wywołuj flush w pętli.

0

Zrobiłem tak jak mówiłeś i nie widać poprawy. Podobnie dzieje się z wykorzystaniem klasy FileCopyUtils z pakietu Springa. Strasznie zapycha JVM. Nie wiem co się dzieje z tą pamięcią. Moze jest jakieś inne podejscie do downloadu plikow z serwera w Springu. Nawet jak nic nie robię, to ona rośnie, a potem jest zwalniana przez GC. Wykres ma kształt piły. Czy jest to normalne, moze są jakies wycieki. Nie mam się z kim skonsultować, bo w tym temacie pracuje sam. Czy ma znaczenie, że używam Spring Webflowa do nawigacji? Może zapamietuje on stany stron (snapshot), aby działał przycisk wstecz i wszystko to siedzi w pamieci?

0

W tej sytuacji musisz zdiagnozować problem. Choć przyznam,że również przesyłam pliki posiadając identyczny kod w servlecie i nie ma problemu
Polecam JProfilera

0

Używałem JProfilera, który potwierdził, że out of memory jest przez download, czasami przez byte[] zajęte było 700-800MB jak testowo pobierałem dużo plików. Nawet uruchomienie GC nie zwalniało za dużo pamięci. Może coś należy skonfigurować w serwerze (WAS); może związane jest to z używaniem webflowa: download jest w akcji flowa: <evaluate expression="fileService.downloadFile(path)" /> i kod w moim pierwszym poście. Nie wiem, czy też dobrze wykorzystałem WebFlow, patrząc na tutoriale i przyklady założyłem i tak skonfigurowalem WebFlowa w xml-u, że każdy punkt menu, to nowy flow.

0

co za obiekt zwraca fileService.downloadFile(path)

0

public void downloadFile(String path) throws Exception

0

To może problemem nie jest operacja wysyłania tylko pobierania. Aby sie o tym przekonac sproboj pobrac duzy plik przegladarka.
Wpisz link np localhost:8080/servletWysylajacyPlik?path=nazwaplik.zip. Wtedy przegladarka powinna otworzyc zwykle okno do pobierania jezeli uda CI sie pobrac plik tzn ze problem lezy po stronie pobierajacego

0

Sciezke do pliku przekazuje we flowie, nie ma nic w pasku adresu przeglądarki dotyczącym pliku. Po nacisnieciu "Pobierz" otwiera mi się standardowe okno przeglądarki do pobierania. Dokładniej mówiąc, kod javy do pobierania nie jest w servlecie (klasie rozszerzajacej HttpServlet), tylko w klasie, do której mam dostep we flowie za pomocą adnotacji. Może od początku mam złe podejście do downloadu plików i przez to moje problemy?

1 użytkowników online, w tym zalogowanych: 0, gości: 1