Загрузка файла 200 МБ через FileReader привела к использованию более 4 ГБ памяти - PullRequest
0 голосов
/ 19 сентября 2019

РЕДАКТИРОВАТЬ: я перешел на использование reader.readAsDataURL(file); и сделал еще пару изменений.Смотрите здесь:

try {
  let file: File = data.file;

  let reader = new FileReader();

  reader.onloadend = (e:any) => {
    this.uploadMessage = 0
    let document = {
      "document_name": file.name,
      "document": reader.result,
      "document_filesize": file.size
    }

    this.myAPI.saveAttachment(document).subscribe(data => {

      if (data && data.message){
        this.uploadMessage = data.message;
      }
      if (this.uploadMessage == 100){
        this.dialogRef.close();
      }
    })
  }

  reader.readAsDataURL(file);
}  

Вышеуказанный подход сокращает потребление памяти до 1 ГБ, все еще выше, чем я ожидал, но управляемо.Однако, чтобы учесть изменение клиента, я обновил бэкэнд, ожидая строки base64, а не необработанного двоичного файла через byte[].Смотрите здесь:

@RequestMapping(value = "/saveAttachment", method = RequestMethod.POST)
public @ResponseBody ResponseEntity<Attachment> postSaveAttachment(@RequestBody Attachment data) {
    ReviewAttachment returnVal = null;                              
    HttpHeaders httpHeaders = new HttpHeaders();
        try {
            Decoder decoder = Base64.getDecoder();
            byte[] decodedByte = decoder.decode(data.getdocument().split(",")[1]);
            FileOutputStream fos = new FileOutputStream(docLoc);
            fos.write(decodedByte);
            fos.close();

            returnVal = AttachmentRepo.save(data);
        }
        catch (Exception e) {
            e.printStackTrace();
            return new ResponseEntity<Attachment>(returnVal, httpHeaders, HttpStatus.NOT_ACCEPTABLE);
        }                             
    return new ResponseEntity<Attachment>(returnVal, httpHeaders, HttpStatus.OK);   
}

Однако, похоже, я только что перенес проблему с памятью на серверную часть.Я уже пытался увеличить Xms / Xmx до 1024 м, но это не помогло.Я получаю это:

JVMDUMP013I Обработанное событие дампа "systhrow", подробно "java / lang / OutOfMemoryError".java / lang / OutOfMemoryError: пространство кучи Java в java / lang / ThreadGroup.uncaughtException (ThreadGroup.java:872) в java / lang / ThreadGroup.uncaughtException (ThreadGroup.java:866) в java / lang / Thread.uncaughtException (поток.java: 1332) Исключение в потоке «https-jsse-nio-8090-AsyncTimeout» java / lang / OutOfMemoryError: пространство кучи Java в java / lang / ThreadGroup.uncaughtException (ThreadGroup.java:872) в java / lang / ThreadGroup.uncaughtException(ThreadGroup.java:866) в java / lang / Thread.uncaughtException (Thread.java:1332)

java.lang.OutOfMemoryError: пространство кучи Java в com.fasterxml.jackson.core.util.TextBuffer.carr (TextBuffer.java:778) ~ [jackson-core-2.8.10.jar! /: 2.8.10] в com.fasterxml.jackson.core.util.TextBuffer.finishCurrentSegment (TextBuffer.java:632) ~ [джексон-core-2.8.10.jar! /: 2.8.10] на com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishString2 (UTF8StreamJsonParser.java:2493) ~ [jackson-core-2.8.10.jar! /:2.8.10] на com.fasterxml.jackson.core.json.UTF8StreamJsonParser._finishAndReturnString (UTF8StreamJsonParser.java:2469) ~ [jackson-core-2.8.10.jar! /: 2.8.10] в com.fasterxml.jackson.core.json.UTF8StreamJsonParser.getText (UTF8StreamJson315).[jackson-core-2.8.10.jar! /: 2.8.10] на com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize (StringDeserializer.java:36) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] at com.fasterxml.jackson.databind.deser.std.StringDeserializer.deserialize (StringDeserializer.java:11) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] вcom.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize (SettableBeanProperty.java:504) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] в com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet (MethodProperty.java:104) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] в com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject (BeanDeserializer.java:35)~ [jackson-databind-2.8.10.jar! /: 2.8.10] на com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize (BeanDeserializer.java:148) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] в com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose (ObjectMapper.java:3814) ~ [джексон-databind-2.8.10.jar! /: 2.8.10] at com.fasterxml.jackson.databind.ObjectMapper.readValue (ObjectMapper.java:2938) ~ [jackson-databind-2.8.10.jar! /: 2.8.10] at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType (AbstractJackson2HttpMessageConverter.java:235) ~ [spring-web-4.3.14.RELEASE.jar! /: 4.3.14.RELEASE]1015 *

Я сейчас просматриваю эту ошибку, но подумал, что я буду обновлять этот пост по мере продвижения.

ORIG:

Моя логика загрузки в Angular Client:

let file: File = data.file;

let reader = new FileReader();
let attachmentArr: any[] = new Array;
let arr;

reader.onload = (e:any) => {
  arr = new Int8Array(e.target.result)
  for (var i = 0; i < arr.length; i++) {
    attachmentArr.push(arr[i]);
  }
};

reader.onloadend = (e:any) => {
  this.uploadMessage = 0
  let document = {
    "document_name": file.name,
    "document": attachmentArr,
    "document_filesize": attachmentArr.length
  }

  this.myAPI.saveAttachment(document).subscribe(data => {
    if (data && data.message){
      this.uploadMessage = data.message;
    }
    if (this.uploadMessage == 100){
      this.dialogRef.close();
    }
  })
}
reader.readAsArrayBuffer(file)
}

Когда я пытаюсь загрузить файл размером около 200 МБ, Chrome предупреждает меня, что он остановил выполнение, чтобы предотвратить ошибку нехватки памяти.Firefox предупредит о длительном запуске скрипта, но если я позволю ему продолжить, загрузка в конечном итоге завершится успешно.Тем не менее, у меня есть 16 ГБ оперативной памяти.Пользователь этого приложения имеет 2 ГБ и получает ошибку нехватки памяти в любом браузере, и загрузка не удалась.

Что мне интересно, так это то, что загрузка файла размером 200 МБ приводит к потреблению памяти объемом в несколько ГБ.Я не думаю, что это имеет какое-либо отношение к Angular, только к FileReader в WebAPI.

...