下载 ZipArchive OutOfMemory
Download ZipArchive OutOfMemory
我在 heroku 应用程序上下载文件时遇到问题。
我有一个基本的 PHP ini,它允许我们有 128MB,用于内存限制。
我的错误如下:
(1/1) OutOfMemoryException Error: Allowed memory size of 134217728
bytes exhausted (tried to allocate 77709312 bytes)
好的,我明白了,但奇怪的是 77709312bytes
只有 74MB。
怎么了?
这是我的下载操作代码:
/**
* @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");
否则,请尝试查明此异常的确切抛出时间,并尝试释放所有不必要的已用内存。
file_get_contents
会将文件加载到内存中,当我将其放入 Response
对象时,这将有效地将所有内容从内存复制到输出缓冲区。这就是为什么 74MB
附近的存档会由于双重工作而导致 Out of memory
for 128M 配置 (74*2) 错误。
此时,我无法使用 readfile()
来解决这个问题,因为行为与我的需要有太多不同。但是 readfile()
将打开并输出到缓冲区而不使用两倍的内存。
编辑:我发现最好的选择是使用 Symfony 3.2 中的 BinaryFileResponse
对象,它可以有效地处理响应流。
你试过了吗file_get_contents($zipName); unlink($zipName);
所以你可以从本地删除文件
我在 heroku 应用程序上下载文件时遇到问题。 我有一个基本的 PHP ini,它允许我们有 128MB,用于内存限制。
我的错误如下:
(1/1) OutOfMemoryException Error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 77709312 bytes)
好的,我明白了,但奇怪的是 77709312bytes
只有 74MB。
怎么了?
这是我的下载操作代码:
/**
* @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");
否则,请尝试查明此异常的确切抛出时间,并尝试释放所有不必要的已用内存。
file_get_contents
会将文件加载到内存中,当我将其放入 Response
对象时,这将有效地将所有内容从内存复制到输出缓冲区。这就是为什么 74MB
附近的存档会由于双重工作而导致 Out of memory
for 128M 配置 (74*2) 错误。
此时,我无法使用 readfile()
来解决这个问题,因为行为与我的需要有太多不同。但是 readfile()
将打开并输出到缓冲区而不使用两倍的内存。
编辑:我发现最好的选择是使用 Symfony 3.2 中的 BinaryFileResponse
对象,它可以有效地处理响应流。
你试过了吗file_get_contents($zipName); unlink($zipName);
所以你可以从本地删除文件