Недостаточно памяти для записи файла base64

Обновлено: 20.11.2024

Скрипт берет json массив из 150-200 base64 изображений размером 700х700рх image/png
Затем собирает их в mp4. Я заметил, что в логах изредка появляются записи:

указываю на строку, где переменная post (где передается 150-200 картинок) преобразуется с помощью json_decode
Как это понять? Пишет что не хватает памяти пытается выделить 256Мб так же 440кб?
200 изображений в формате base64 весят меньше, чем вся память.

  • 3 Как это сделать в laravel?
  • 2 Как подключиться к локальной сети через спутниковый интернет?
  • 2 Можно ли завершить работу одновременно с подсистемой windows и linux?
  • 1 Как реализовать фильтрацию и сортировку контента на странице в FLask?
  • 2 Менеджер по продукту или специалист по данным – у кого выше SN?
  • 2 Чтобы PHP выполнял exec в очереди?
  • 1 Как сделать этот слайдер Swiper?
  • 1 Как сгенерировать код 404 в Angular Universal?

Ваша версия FormData - очень хороша! Во-первых, кодировка base64 всегда увеличивает исходный размер закодированных данных, а во-вторых, для парсинга JSON он должен быть полностью загружен в память, т.е. вы и строка пришли все в память и результирующий объект JSON в память.

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

Спасибо за ответ! И как лучше будет из пака 200 файлов отправить или 1 файл как предложила ariane.Little?
Pack, если вам нужно увеличить лимит на количество принимаемых файлов PHP, но если 1, процесс передачи может быть дольше из-за самих запросов + блокировка может быть Nginx для частых запросов.
Даже не знаю, как лучше с точки зрения грамотного подхода. - прокомментировала thelma.Bednar 4 апреля 20 в 00:19

@Jorge_Marvin, лучше отправить все файлы, я все файлы загрузки переложил в самом nginx.
Я даже не уверен, что браузер может просто скачать 200 файлов один за другим. - прокомментировал jace63 4 апреля 20 в 00:22

@lea_Gaylord , а такое возможно на самом деле? Nginx действительно быстрее может быть в этом плане. - прокомментировала thelma.Bednar 4 апреля 20 в 00:25

@lea_Gaylord, не подскажете, как заливать файлы с помощью nginx? нужен этот дополнительный модуль или стандартные инструменты есть? - прокомментировала thelma.Bednar 4 апреля 20 в 00:28

@lea_Gaylord, он динамически подключается? Прочитал вроде можно подключать модули пересборкой:

откройте nginx.conf:
sudo nano /etc/nginx/nginx.conf
добавьте в основной контекст следующее:
load_module "modules/ngx_http_geoip_module.so";

C nginx-upload-module, кроме этого, произойдет? - прокомментировала thelma.Bednar 4 апреля 20 в 00:34

@Jorge_Marvin на самом деле является модулем geoip, есть большая вероятность, что модуль уже есть.
Похоже, что даже вызов версии nginx показывает модули: nginx -v - jace63 прокомментировал 4 апреля 20 в 00:37

@lea_Gaylord, это не похоже на модуль по выдаче nginx -V - thelma. Прокомментировал Беднар 4 апреля 20 в 00:43

@lea_Gaylord кстати тут написать модуль есть проблемы на некоторых версиях, а потом есть опция clientBodyInFileOnly он будет?
Чем заменить nginx-upload-module?

Приведенный ниже код предназначен для преобразования zip-файла в формат base64.

Сначала я попытался использовать zip-файл размером 3 МБ. Все работало нормально. Но когда я пытаюсь использовать zip-файл размером 34 МБ, он говорит:

Недостаточно памяти для завершения этой операции!

Есть ли какой-либо способ обработки zip-файлов всех размеров, поскольку размер моих файлов в основном составляет 30 МБ или больше?

Как это может помочь? Я читал некоторые связанные вопросы по Java, и они говорят о разделении файла и его чтении.

1 Ответ 1

отредактировано 10 января 2017 г. - (исходный ответ сохранен внизу)

отредактировано 10 января 2017 г. - (снова) - некоторые (не все) мои проблемы с тайм-аутами были вызваны сбоем диска.

Проблемы с входными данными решались путем разделения операций преобразования. Теперь код был изменен для обработки буферизации двумя разными способами: для небольших файлов (по умолчанию настроенных для файлов до 10 МБ) поток памяти используется для хранения вывода, а для больших файлов (более 10 МБ) используется временный файл. (см. примечания после кода).

Будет ли проблема с памятью?

Да. Доступная память по-прежнему является пределом. Во всяком случае, я протестировал код с cscript.exe, работающим как 32-битный процесс с файлами размером 90 МБ и в 64-битном режиме с файлами размером 500 МБ без проблем.

Почему два метода?

Метод потока быстрее (все операции выполняются в памяти без конкатенации строк), но он требует больше памяти, так как в конце функции будет две копии одних и тех же данных: внутри потока будет одна копия и один в строке, которая будет возвращена

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

Ограничение в 10 МБ, используемое для определения того, будем ли мы использовать временный файл, является просто пессимистичной конфигурацией для предотвращения проблем в 32-битном режиме. Я без проблем обработал файлы размером 90 МБ в 32-битном режиме, но просто для безопасности.

Почему поток настроен как Unicode, а данные извлекаются с помощью метода .Read()?

Потому что функция stream.ReadText() работает медленно. Внутри он выполняет множество преобразований/проверок строк (да, это рекомендуется в документации), что делает его непригодным для использования в данном случае.

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

Разделить процесс чтения/кодирования

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

3145716 — это ближайшее кратное 54 (количество входных байтов для каждой строки вывода base64), меньшее, чем 3145728 (3 МБ).

Этот класс реализует кодировщик для кодирования байтовых данных с использованием схемы кодирования Base64, как указано в RFC 4648 и RFC 2045.

Экземпляры класса Base64.Encoder безопасны для использования несколькими параллельными потоками.

Если не указано иное, передача нулевого аргумента методу этого класса вызовет исключение NullPointerException.

Краткое описание метода

Все методы Экземпляры Методы Конкретные методы
Модификатор и тип Метод и описание
byte[] encode (byte[] src)

Кодирует все байты из указанного массива байтов в новый выделенный массив байтов, используя схему кодирования Base64.

Кодирует все байты из указанного массива байтов, используя схему кодирования Base64, записывая полученные байты в заданный выходной массив байтов, начиная со смещения 0.

Кодирует все оставшиеся байты из указанного буфера байтов во вновь выделенный буфер байтов, используя схему кодирования Base64.

Возвращает экземпляр кодировщика, который кодирует эквивалентно этому, но без добавления какого-либо символа заполнения в конце закодированных байтовых данных.

Методы, унаследованные от класса java.lang.Object

Сведения о методе

кодировать

Кодирует все байты из указанного массива байтов в новый выделенный массив байтов, используя схему кодирования Base64. Возвращаемый массив байтов имеет длину результирующих байтов.

кодировать

Кодирует все байты из указанного массива байтов, используя схему кодирования Base64, записывая полученные байты в заданный выходной массив байтов, начиная со смещения 0.

Вызывающий этот метод обязан убедиться, что в выходном массиве байтов dst достаточно места для кодирования всех байтов из входного массива байтов. Никакие байты не будут записаны в выходной массив байтов, если выходной массив байтов недостаточно велик.

кодировать в строку

Этот метод сначала кодирует все входные байты в массив байтов в кодировке base64, а затем создает новую строку с использованием массива закодированных байтов и набора символов ISO-8859-1.

Другими словами, вызов этого метода имеет тот же эффект, что и вызов new String(encode(src), StandardCharsets.ISO_8859_1) .

кодировать

Кодирует все оставшиеся байты из указанного буфера байтов во вновь выделенный буфер байтов, используя схему кодирования Base64. По возвращении позиция исходного буфера будет обновлена ​​до предела; его предел не будет изменен. Позиция возвращаемого выходного буфера будет равна нулю, а его пределом будет количество результирующих закодированных байтов.

Рекомендуется сразу же закрыть возвращенный поток вывода после использования, во время которого он сбросит все возможные оставшиеся байты в базовый поток вывода. Закрытие возвращенного выходного потока закроет базовый выходной поток.

без заполнения

Возвращает экземпляр кодировщика, который кодирует эквивалентно этому, но без добавления какого-либо символа заполнения в конце закодированных байтовых данных.

Этот вызов не влияет на схему кодирования этого экземпляра кодировщика. Возвращенный экземпляр кодировщика следует использовать для операции кодирования без заполнения.

  • Обзор:
  • Вложенный |
  • Поле |
  • Констр |
  • Подробности:
  • Поле |
  • Констр |

Сообщите об ошибке или функции.
Дополнительные справочные материалы по API и документацию для разработчиков см. в документации по Java SE. Эта документация содержит более подробные описания, предназначенные для разработчиков, с концептуальными обзорами, определениями терминов, обходными путями и примерами рабочего кода.
Авторские права © 1993, 2022, Oracle и/или ее дочерние компании. Все права защищены. Использование регулируется условиями лицензии. Также ознакомьтесь с политикой распространения документации.

Многие интернет-форматы, от электронной почты (MIME) до Интернета (HTML/CSS/JavaScript), являются только текстовыми. Если вы отправляете изображение или исполняемый файл по электронной почте, оно часто сначала кодируется с использованием base64. Хитрость кодировки base64 заключается в том, что мы используем 64 различных символа ASCII, включая все буквы, верхний и нижний регистр и все цифры.

Звучит плохо. Как инженеры могут терпеть такие расточительные форматы?

Веб-серверы обычно предоставляют контент в сжатой форме. Сжатие частично компенсирует расточительный характер base64.

Чтобы оценить эффект кодирования base64, я выбрал набор изображений, использованных в недавней исследовательской работе. Существуют разные форматы сжатия, но старым форматом является gzip. Я кодирую изображения с помощью base64, а затем сжимаю их с помощью gzip. Сообщаю количество байт. Я делаю файлы доступными.

Имя файла Размер Размер Base64 Размер base64 gzip
bing.jpg 1355 1832 1444
логотип Google .jpg 2357 3186 2477
lena_color_512.jpg 105764 142876 108531
mandril_color.jpg 247222 333970 253868
peppers_color.jpg 9478 12807 9798< /td>

Как видите, размеры gzip не превышают 5 % исходных размеров. А для больших файлов разница ближе к 2,5%.

Таким образом, вы можете безопасно использовать base64 в Интернете без особых опасений.

В некоторых случаях кодирование base64 может даже повысить производительность, так как позволяет избежать отдельных запросов к серверу. В других случаях base64 может усугубить ситуацию, поскольку имеет тенденцию побеждать кэширование браузера и сервера. С точки зрения конфиденциальности кодировка base64 может иметь преимущества, поскольку она скрывает содержимое, к которому вы получаете доступ, в больших зашифрованных пакетах.

Дополнительная литература. Более быстрое кодирование и декодирование Base64 с использованием инструкций AVX2, Транзакции ACM в Интернете, 12 (3), 2018 г. См. также статью Ричарда Стартина «Совместное сжатие».

Читайте также: