рассмотрим следующий простой PHP-скрипт:
<?php
print memory_get_usage()."<br />";
print ini_get("memory_limit")."<br />";
$file = imagecreatefromjpeg("image.jpg");
?>
Вывод следующий:
109848
120M
Fatal error: Out of memory (allocated 63700992) (tried to allocate 23040 bytes) in /homepages/13/d444038670/htdocs/bilderarchiv/test.php on line 4
Картинка, которую я пытаюсь прочитать, — это большая картина. Однако во второй строке указано, что memory_limit равен 120 МБ, но сценарий умирает с выделением около 64 МБ. Как это может быть? Скрипт отлично работает на другом провайдере, хотя memory_limit там тоже 120M.
Вам не хватает памяти, но есть решение.
Попробуйте запустить это на обоих ваших серверах, чтобы определить, сколько памяти требуется на пиксель изображения:
<?php
$mem0 = memory_get_usage(true);
$megapix = imagecreatetruecolor(1000,1000);
$mem1 = memory_get_usage(true);
$memdif = $mem1 - $mem0;
$perpixel = $memdif / (1000 * 1000);
echo "<pre>1 million pixel memory test
before imagecreate: $mem0
after imagecreate: $mem1
image memory used: $memdif
bytes per pixel: $perpixel";
?>
Я получил эти результаты:
1 million pixel memory test (Linux)
before imagecreate: 524288
after imagecreate: 5505024
image memory used: 4980736
bytes per pixel: 4.980736
1 million pixel memory test (Windows)
before imagecreate: 262144
after imagecreate: 5505024
image memory used: 5242880
bytes per pixel: 5.24288
При размере 5 байт на пиксель для вашего изображения 5760×3240 потребуется 89 МБ.
Чтобы увидеть, требуется ли imagecreatefromjpeg много временной памяти сверх 89 МБ, необходимых для изображения, сравните memory_get_usage
с memory_get_peak_usage
сразу после загрузки изображения. В моем тестировании не было значительного.
(Старые версии GD использовали 4 байта, я думаю.)
Затем выясните, сколько памяти у вас действительно есть:
<?php
echo 'memory_limit ??? ', ini_get('memory_limit'), '<br>';
$megs = Array();
for ( $i=0; $i < 1000; ++$i ) { // try up to 1000MB
$megs[] = str_repeat('*', 1048000);
$mb= round(memory_get_usage(true) / 1024/1024);
echo "$mb ";
flush();
ob_flush();
}
?>
Если вы не получаете никакого вывода, вероятно, происходит буферизация, которую вы не можете отключить, поэтому просто попробуйте другие верхние пределы в for
цикл, пока вы не найдете самый большой, который все еще работает.
Одно решение
Я давно отказался от GD для уменьшения больших изображений в формате JPEG и вместо этого использовал ImageMagick. Если вы выполняете его из PHP, это отдельный процесс, поэтому ограничение памяти PHP больше не применяется. Конечно, в конечном итоге существует ограничение памяти, но вы можете указать ImageMagick максимальный объем используемой памяти.
(Я также получил изображения лучшего качества, чем с GD.)
Других решений пока нет …