This function is passed about 70k objects to process. It has no problem loading the array, and it gets through about half the iterations before it fails. Memory is limited to ini_set('memory_limit','465M'); (cloud service). It always fails in the $googleFunction: /app/vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php.
I've already tried passing the array as a reference, switching from array_chunk to using an array_slice at a time, passing the $chunk by reference to the $googleFunction, unsetting the $chunk at the end, and calling gc_collect_cycles() after each iteration.
How can it still fail? There must be a memory leak somewhere, but there are no large assignments aside from $chunk and $result, and each function called goes out of scope during each iteration, so anything it may have allocated is supposed to be garbage collected. I feel it may have something to do with the function references. After about a quarter of the iterations, it uses 240M. It grows by about 10M per iteration.
function googleJob($job = null, &$list, $googleFunction, $before = null) {
// initialize $total, $gaw, $processed
for ($chunkIndex = 0; $chunkIndex < count($list); $chunkIndex += 2000) {
echo '3:'.memory_get_usage().' ';
$chunk = array_slice($list, $chunkIndex, 2000); # limit of 2000/request
echo '4:'.memory_get_usage().' ';
if ($before) {
foreach ($chunk as $item) {
$before($item); # function reference
}
}
echo '5:'.memory_get_usage().' ';
$i = 0; // try harder to make Google work
$result = null;
do {
try {
$result = $gaw->$googleFunction($chunk);
echo '6:'.memory_get_usage().' ';
} catch (\SoapFault $e) { # try to remove the bad items and try again
// no errors generated
}
} while ($result == null && $chunk); // Retry the request if not empty
array_walk($chunk, function($item) { $item->save(); });
echo '7:'.memory_get_usage().' ';
$processed += count($chunk);
if ($job) {
$job->progress = round($processed / $total * 100);
$job->save() or Yii::error($job->getErrors());
}
echo '8:'.memory_get_usage().' ';
unset($chunk);
unset($result);
echo '9:'.memory_get_usage().'... ';
gc_collect_cycles();
echo memory_get_usage().PHP_EOL;
}
}
Memory 'profiling' output:
3:110267832 4:110372112 5:111920328 6:123908368 7:129432080 8:129432080 9:121662520... 121662520
3:121662520 4:121766800 5:123281704 6:138001000 7:143493888 8:143493888 9:135745264... 135745264
$listas a reference, because you never modify that array.$item->save()do? That looks like the only part of the function that will use lots of memory, because it saves every input item somewhere.$gaw->$googleFunctionsave$chunkanywhere?