如何为此函数优化 PHP 中的内存使用?
How do I optimize memory usage in PHP for this function?
此函数传递了大约 70k 个对象进行处理。它加载数组没有问题,并且在失败之前通过了大约一半的迭代。内存限制为 ini_set('memory_limit','465M');
(云服务)。它总是在 $googleFunction
: /app/vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php
中失败。
我已经尝试过将数组作为引用传递,一次从 array_chunk
切换到使用 array_slice
,通过引用传递 $chunk
[=14] =],最后取消设置 $chunk
,并在每次迭代后调用 gc_collect_cycles()
。
怎么还会失败呢?某处肯定有内存泄漏,但除了 $chunk
和 $result
之外没有大的分配,并且每个调用的函数在每次迭代期间都超出范围,所以它可能分配的任何东西都应该是收集的垃圾。我觉得这可能与函数引用有关。经过大约四分之一的迭代后,它使用了 240M。它每次迭代增长约 10M。
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;
}
}
内存'profiling'输出:
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
我觉得你在滥用肥皂服务。如果您告诉我们您的代码在 $googleFunction 处失败,我可以建议您将 $chunk 设置为 100 或 200 个对象。
第二个是 $item->save() 函数。如果您有权访问 class,您应该检查是否有 HAS-IS classes。唯一 PHP 泄漏内存的地方是这样的结构:
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
for($i = 0; $i < 10; $i++){
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "<br>";
}
所以如果您有对象,我怀疑是在 save() 函数中创建的 Active Record 对象,请不要忘记取消设置它们。
简单的方法是像这样添加 destruct:
function __destruct()
{
unset($this->bar);
}
这应该有帮助
此函数传递了大约 70k 个对象进行处理。它加载数组没有问题,并且在失败之前通过了大约一半的迭代。内存限制为 ini_set('memory_limit','465M');
(云服务)。它总是在 $googleFunction
: /app/vendor/googleads/googleads-php-lib/src/Google/Api/Ads/Common/Lib/AdsSoapClient.php
中失败。
我已经尝试过将数组作为引用传递,一次从 array_chunk
切换到使用 array_slice
,通过引用传递 $chunk
[=14] =],最后取消设置 $chunk
,并在每次迭代后调用 gc_collect_cycles()
。
怎么还会失败呢?某处肯定有内存泄漏,但除了 $chunk
和 $result
之外没有大的分配,并且每个调用的函数在每次迭代期间都超出范围,所以它可能分配的任何东西都应该是收集的垃圾。我觉得这可能与函数引用有关。经过大约四分之一的迭代后,它使用了 240M。它每次迭代增长约 10M。
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;
}
}
内存'profiling'输出:
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
我觉得你在滥用肥皂服务。如果您告诉我们您的代码在 $googleFunction 处失败,我可以建议您将 $chunk 设置为 100 或 200 个对象。
第二个是 $item->save() 函数。如果您有权访问 class,您应该检查是否有 HAS-IS classes。唯一 PHP 泄漏内存的地方是这样的结构:
class Foo {
function __construct()
{
$this->bar = new Bar($this);
}
}
class Bar {
function __construct($foo = null)
{
$this->foo = $foo;
}
}
for($i = 0; $i < 10; $i++){
$foo = new Foo();
unset($foo);
echo number_format(memory_get_usage()) . "<br>";
}
所以如果您有对象,我怀疑是在 save() 函数中创建的 Active Record 对象,请不要忘记取消设置它们。 简单的方法是像这样添加 destruct:
function __destruct()
{
unset($this->bar);
}
这应该有帮助