Превышено ограничение на загрузку больших файлов, что привело к превышению предельных значений GC - PullRequest
0 голосов
/ 19 апреля 2019

У меня есть два сервиса: первый frontend_service и второй backend_service, и я получаю большой файл из backend_service и пытаюсь переслать его пользователю через frontend_service, используя response.getBodyAsStream (), но это вызывает "java.lang.OutOfMemoryError: Превышен предел накладных расходов GC" в frontend_service.

код для backend_service:

`

public static Result downloadLargeFile(String filePath){
   File file = new File(filePath);
   InputStream inputStream = new FileInputStream(file);
   return ok(inputStream);
}

`

код для frontend_service:

`

  public static F.Promise<Result> downloadLargeFile(String filePath) {
       //this will call backend_service downloadLargeFile method.
       String backEndUrl = getBackEndUrl(filePath);
       return getInputStream(backEndUrl);
    }

`

`

public static Promise<Result> getInputStream(String url) {
            return WS.url(url).get().map(
                    response -> {
                        InputStream inputStream =  response.getBodyAsStream();
                        return ok(inputStream);
                    }
            );
}

`

Я попробовал предлагаемое решение здесь , считывая несколько байтов за раз из inputStream и создавая файл tmp в frontend_service и отправляя файл tmp в качестве вывода из frontend_service.

`

    public static Promise<Result> getInputStream(String url) {
            return WS.url(url).get().map(
                    response -> {
                        InputStream inputStream = null;
                        OutputStream outputStream = null;
                        try {
                            inputStream =  response.getBodyAsStream();
                            //write input stream to tmp file
                            final File tmpFile = new File("/tmp/tmp.txt");
                            outputStream = new FileOutputStream(tmpFile);

                            int read = 0;
                            byte[] buffer = new byte[500];
                            while((read = inputStream.read(buffer)) != -1){
                                outputStream.write(buffer, 0 , read);
                            }
                            return ok(tmpFile);
                        } catch (IOException e) {
                            e.printStackTrace();
                            return badRequest();
                        } finally {
                            if (inputStream != null) {inputStream.close();}
                            if (outputStream != null) {outputStream.close();}
                        }
                    }
            );

`

Выше кода также выдается java.lang.OutOfMemoryError. Я пытаюсь 1 ГБ файла.

1 Ответ

0 голосов
/ 23 апреля 2019

У меня нет реализации «под рукой», поэтому я напишу алгоритм.

1.Play использует AsyncHttpClient под WS.Вам нужно получить его или создать, как описано в https://www.playframework.com/documentation/2.3.x/JavaWS#Using-WSClient

2.Затем необходимо реализовать AsyncCompletionHandler, как в описании класса https://static.javadoc.io/org.asynchttpclient/async-http-client/2.0.0/org/asynchttpclient/AsyncHttpClient.html

3.В методе onBodyPartReceived класса AsyncCompletionHandler вам необходимо подтолкнуть часть тела к ответу фрагментированного воспроизведения.Чеканированные ответы описаны здесь: https://www.playframework.com/documentation/2.3.x/JavaStream#Chunked-responses

PS

Обсуждение аналогичного решения, но в противоположном направлении - потоковая загрузка в службу "бэкэнд" (Amazon) через "внешний интерфейс" (игра2) услуга: https://groups.google.com/d/msg/asynchttpclient/EpNKLSG9ymM/BAGvwl0Wby8J

...