简体   繁体   English

如何为此功能优化PHP中的内存使用情况?

[英]How do I optimize memory usage in PHP for this function?

This function is passed about 70k objects to process. 此函数传递约70k对象进行处理。 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'); 内存限制为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 . 它总是在$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. 我已经尝试过将数组作为引用传递,一次从array_chunk切换为使用array_slice ,将$chunk通过引用传递给$googleFunction ,最后$googleFunction设置$chunk ,并在每次迭代后调用gc_collect_cycles()

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. 某处一定有内存泄漏,但是除了$chunk$result之外,没有其他大的分配,并且每个调用的函数在每次迭代期间都超出范围,因此应该分配的任何内容都应该被垃圾回收。 I feel it may have something to do with the function references. 我觉得这可能与函数引用有关。 After about a quarter of the iterations, it uses 240M. 经过大约四分之一的迭代,它使用了240M。 It grows by about 10M per iteration. 每次迭代增长约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;
    }
  }

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

It seems to me you are abusing soap service. 在我看来,您正在滥用肥皂服务。 if you telling us that your code fails at $googleFunction I can offer you set the $chunk with 100 or 200 objects. 如果您告诉我们您的代码在$ googleFunction中失败,那么我可以为您设置$ chunk包含100或200个对象。

The second thing is a $item->save() function. 第二件事是$ item-> save()函数。 If you have an access to the class you should check if there are HAS-IS classes. 如果可以访问该类,则应检查是否有HAS-IS类。 The only place PHP leak the memory is like this construction: 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>";

} 

so If you have objects, I suspect Active Record objects, created in a save() function don't forget to unset them. 因此,如果您有对象,我怀疑在save()函数中创建的Active Record对象不会忘记取消设置它们。 the easy way is to add destruct like this: 最简单的方法是添加以下破坏:

function __destruct()
    {
        unset($this->bar);
    }

This should help 这应该有帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM