Как я могу избежать ошибок OutOfMemoryErrors при использовании DiskFileItem Commons FileUpload для загрузки больших файлов?

Я получаю OutOfMemoryErrors при загрузке больших (> 300 МБ) файлов в сервлет с использованием Commons FileUpload 1.2.1. Это кажется странным, потому что весь смысл использования DiskFileItem состоит в том, чтобы предотвратить размещение (возможно, большого) файла в памяти. Я использую порог размера по умолчанию 10 КБ, так что это все, что нужно загрузить в кучу, верно? Вот частичная трассировка стека:

java.lang.OutOfMemoryError
       at java.io.FileInputStream.readBytes(Native Method)
       at java.io.FileInputStream.read(FileInputStream.java:177)
       at org.apache.commons.fileupload.disk.DiskFileItem.get(DiskFileItem.java:334)
       at org.springframework.web.multipart.commons.CommonsMultipartFile.getBytes(CommonsMultipartFile.java:114)

Почему это происходит? Есть ли какая-то конфигурация, которую мне не хватает? Любые советы/рекомендации, чтобы избежать этой ситуации, помимо увеличения размера кучи?

Я действительно не должен увеличивать свою кучу, потому что теоретически максимум, что должно быть загружено в память от этой операции, составляет чуть более 10 КБ. Кроме того, мой максимальный размер кучи (-Xmx) уже установлен на 1 ГБ, чего должно быть достаточно.


person Robert Campbell    schedule 07.11.2009    source источник


Ответы (2)


Имея дело с загрузкой файлов, особенно больших, вы должны обрабатывать эти файлы как потоки, которые вы загружаете в буфер среднего размера в памяти и копируете непосредственно в выходной файл. Неправильный способ сделать это — впитать все это в память, прежде чем записать.

Документ по commons-upload упоминает чуть ниже середины, как "Обработать файл загрузить". Если вы не забываете копировать из входного потока в выходной поток кусками разумного размера (скажем, 1 МБ), у вас не должно возникнуть проблем.

person Carl Smotricz    schedule 07.11.2009
comment
Сначала я не думал, что ваш комментарий относится к моей ситуации, потому что я не обрабатывал файл напрямую; Я оборачивал экземпляры FileItem в класс MultipartFile Spring. Однако я присмотрелся к коду и обнаружил, что он вызывает метод getBytes() MultipartFile, который возвращает все содержимое файла. Я развернул свой FileItem из MultipartFile, затем обработал файлы, как рекомендовано в документации. Это решило мою проблему. - person Robert Campbell; 07.11.2009

Хотя ответ Карла Смотрица, вероятно, лучше в общем случае, исключение, которое вы получаете, - это ошибка JVM, о которой сообщается здесь:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6478546

person Daniel Rejment    schedule 18.04.2012