Force GC in GDBackend

This has been discussed previously, and was assumed to be handled by PHP automatically:
https://github.com/silverstripe/silverstripe-framework/issues/2739#issuecomment-32603005
It’s unclear if its a regression in SS4.

Tested with PHP 5.6.29, by setting xdebug breakpoints
and inspecting memory_get_usage() before and after GDBackend->manipulateImage().
Even a single 7MB JPEG straight from my DSLR (6000x300) can chomp bring the system from 30MB to >128MB memory use.
That’s in addition to the 7MB of PHP memory required for the $content variable.
Note that the image manipulations likely happen on the raw bitmap, which is much larger than the 7MB compressed JPEG.

Checked ImagickBackend, which doesn’t have this issue (and only uses about half the memory for the same set of images).
This commit is contained in:
Ingo Schommer 2017-01-06 15:15:46 +13:00
parent 9ee3be9337
commit 6e561f00bd
2 changed files with 17 additions and 1 deletions

View File

@ -73,6 +73,13 @@ class GDBackend extends Object implements Image_Backend, Flushable
}
}
public function __destruct()
{
if ($resource = $this->getImageResource()) {
imagedestroy($resource);
}
}
public function loadFrom($path)
{
// If we're working with image resampling, things could take a while. Bump up the time-limit

View File

@ -733,13 +733,22 @@ trait ImageManipulation
return null;
}
return $backend->writeToStore(
$return = $backend->writeToStore(
$store,
$filename,
$hash,
$variant,
array('conflict' => AssetStore::CONFLICT_USE_EXISTING)
);
// Enforce garbage collection on $backend, avoid increasing memory use on each manipulation
// by holding on to the underlying GD image resource.
// Even though it's a local variable with no other references,
// PHP holds on to it for the entire lifecycle of the script,
// which is potentially related to passing it into the $callback closure.
gc_collect_cycles();
return $return;
}
);
}