У меня проблема при загрузке файла в моем приложении heroku. У меня есть базовый ini PHP, который позволяет нам иметь 128 МБ для ограничения памяти.
Моя ошибка выглядит следующим образом:
(1/1) OutOfMemoryException Error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 77709312 bytes)
Хорошо, я понял, но странно то, что 77709312bytes всего 74 МБ.
Так что не так?
Это код моего действия загрузки:
/**
* @Route("/templates/{id}/download", name = "api_templates_download", requirements = {"id" = "\d+"})
* @Method({"GET"})
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response
* @throws \Exception
*/
public function downloadTemplate(Request $request)
{
$id = $request->get('id');
try {
$template = $this->service->getTemplate($id, $this->helper->getUser());
$archive = $this->service->downloadTemplate($template);
$response = new Response(file_get_contents($archive));
$response->headers->set('Content-Type', 'application/zip');
$response->headers->set('Content-Disposition', 'attachment;filename = "' . $archive . '"');
$response->headers->set('Content-length', filesize($archive));
return $response;
} catch (\Exception $e) {
$response = new Response(json_encode($e->getMessage()), 401);
$response->headers->set('Content-Type', 'application/json');
return $response;
}
}
И метод downloadTemplate вызвал в контроллере:
/**
* @tests Need to tests about performance - do this in September with real server
* @param \App\Domain\Dollycast\Template\Entity\Template $template
* @return string
*/
public function downloadTemplate(Template $template)
{
$zip = new \ZipArchive();
$zipName = self::ZIPDIR . $template->getName() . '.zip';
$zip->open($zipName, \ZipArchive::CREATE);
$finder = new Finder();
$finder->files()->in(self::WORKDIR . $template->getName());
$zip->addEmptyDir($template->getName());
/** @var SplFileInfo $file */
foreach ($finder as $file) {
// Rename the full path to the relative Path
$zip->addFile(
self::WORKDIR . $template->getName() . DIRECTORY_SEPARATOR . $file->getRelativePathname(),
$template->getName() . DIRECTORY_SEPARATOR . $file->getRelativePathname()
);
}
$zip->close();
return $zipName;
}






(1/1) OutOfMemoryException Error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 77709312 bytes)
В то время процесс php пытается выделить 77709312 байт, для которого уже выделена память, что можно проверить с помощью функции memory_get_usage (). В вашем случае это должно быть больше (134217728 - 77709312 =) 56508416 байт.
Если во время создания zip-файла возникает исключение, вы можете попробовать использовать внешний инструмент для создания zip-файла. Что-то вроде
exec("tar -zcvf archive.tar.gz /folder/tozip");
В противном случае попытайтесь узнать, когда именно возникает это исключение, и попытайтесь освободить всю ненужную используемую память.
Не думайте, потому что у меня в архиве около 77709312 МБ. Кроме того, в сообщении об ошибке говорится не о дополнительных байтах, а об общем количестве байтов.
Процесс пытается выделить 77709312 байт, но это невозможно, потому что тогда он превысит максимум 134217728 байт, потому что в данный момент ваше приложение уже использует больше, чем (134217728 - 77709312 =) 56508416 байт.
Вы знаете, в какой строке произошла ошибка? При создании zip-архива или в "file_get_contents ($ archive)"?
file_get_contents загрузит файл в память, когда я помещу его в объект Response, это эффективно скопирует все содержимое из памяти в выходной буфер. Вот почему архив около 74MB приведет к ошибке Out of memory для конфигурации 128M (74 * 2) из-за двойной работы.
В настоящее время я не могу использовать readfile() для решения этой проблемы, потому что поведение слишком сильно отличается для моих нужд. Но readfile() будет открываться и выводиться в буфер без использования двойной памяти.
Обновлено: Лучшая альтернатива, которую я нашел, - это использование объекта BinaryFileResponse из Symfony 3.2, который эффективно обрабатывает поток ответов.
Вы пробовали file_get_contents($zipName); unlink($zipName);, чтобы вы могли удалить файл из локального
Привет, спасибо, но это не относится к моей проблеме, взгляните на мой ответ: p
Я знаю, что просто хотел указать на отключение, чтобы не хранить большой zip-файл :)
Я также предлагаю использовать file_get_contents ($ archive) на вашей логической стороне :)