问题
I need a PHP CLI script to do various image transformations via GD functions. The images are quite big so I need to squeeze as much memory as possible. However, imagedestroy() seems not to release memory when asked.
Consider following demo script 'test.php':
#!/usr/bin/php5
<?php
$memory = [0=> memoryCheck()];
$res1 = imagecreatetruecolor(8192, 4096);
memoryReport('Res1 created');
$res2 = imagecreatetruecolor(8192, 4096);
memoryReport('Res2 created');
imagedestroy($res1);
memoryReport('Res1 destroyed');
imagedestroy($res2);
memoryReport('Res2 destroyed');
// memory reporting functions follow:
function memoryCheck()
{
return (int) trim(substr(shell_exec('free -b'), 166, 11));
}
function format($value)
{
$val = \abs($value);
$unit=array('B','kiB','MiB','GiB','TiB','PiB');
return @round($val/pow(1024,($i=floor((($val==0)?0:log($val,1024))))),2).' '.$unit[$i];
}
function memoryReport($msg)
{
global $memory;
$start = $memory[0];
$prev = end($memory);
$now = memoryCheck();
echo sprintf("%s: %s (%s)\n",
$msg,
format($now-$start),
(($diff=$now-$prev) <0) ? '-'. format($diff) : '+'. format($diff)
);
$memory[] = $now;
}
?>
Let's run it by issuing:
free -m;./test.php;free -m
Example results:
total used free shared buffers cached
Mem: 7890 7072 818 561 218 2497
-/+ buffers/cache: 4355 3534
Swap: 8299 0 8299
Res1 created: 109.76 MiB (+109.76 MiB)
Res2 created: 218.77 MiB (+109.01 MiB)
Res1 destroyed: 218.9 MiB (+140 kiB)
Res2 destroyed: 888 kiB (-218.04 MiB)
total used free shared buffers cached
Mem: 7890 7072 817 561 218 2498
-/+ buffers/cache: 4356 3534
Swap: 8299 0 8299
As you can see, creating one image costs 109-110MB. After creating second one we have double that used up. But destroying first doesn't release memory. All the resources' memory gets released only after both images are destroyed.
Why? Have I overlooked something? What should I do to amend it?
UPDATE: I added setting $res1 to null and then unsetting it altogether. Code:
$memory = [0=> memoryCheck()];
$res1 = imagecreatetruecolor(8192, 4096);
memoryReport('Res1 created');
$res2 = imagecreatetruecolor(8192, 4096);
memoryReport('Res2 created');
imagedestroy($res1);
memoryReport('Res1 destroyed');
$res1 = null;
memoryReport('Res1 is null');
unset($res1);
memoryReport('Res1 is unset');
imagedestroy($res2);
memoryReport('Res2 destroyed');
Now result is:
Res1 created: 109.48 MiB (+109.48 MiB)
Res2 created: 219.33 MiB (+109.85 MiB)
Res1 destroyed: 219.5 MiB (+168 kiB)
Res1 is null: 220.15 MiB (+668 kiB)
Res1 is unset: 220.38 MiB (+232 kiB)
Res2 destroyed: 2 MiB (-218.36 MiB)
Also, I added
gc_collect_cycles();
memoryReport('GC collect');
right before imagedestroy($res2); and then things go strange:
Res1 created: 109.59 MiB (+109.59 MiB)
Res2 created: 219.08 MiB (+109.5 MiB)
Res1 destroyed: 219.21 MiB (+132 kiB)
Res1 is null: 219.36 MiB (+148 kiB)
Res1 is unset: 219.75 MiB (+408 kiB)
GC collect: 220.57 MiB (+836 kiB)
Res2 destroyed: 220.46 MiB (-108 kiB)
According to 'free' command, the memory gets released only after script ended.
回答1:
I wonder if it's GC... try running gc_collect_cycles()
after imagedestroy()
. Long shot, but you never know...
来源:https://stackoverflow.com/questions/32320212/why-gd-doesnt-release-memory-upon-imagedestroy