【问题标题】:Laravel Daemon Queue Memory LeakLaravel 守护进程队列内存泄漏
【发布时间】:2016-08-31 09:02:40
【问题描述】:

我正在使用 laravel 5.1 并使用主管来监控队列作业。队列驱动程序是数据库。

[program:queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work database --sleep=3 --tries=1 --daemon
autostart=true
autorestart=true
user=root
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/html/storage/logs/supervisord.log

队列侦听器使用的 RAM 在处理每个作业后会增加,最高可达 150-200 MB。所有全局变量都赋值为 null。

namespace App\Jobs;
use App\Jobs\Job;
use App\Compatibility;
use App\Like;
use App\Message;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;

class CalculateInteractionLike extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;
    protected $userAId;
    protected $userBId;
    protected $gender;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($userAId, $userBId, $gender)
    {
        $this->userAId = $userAId;
        $this->userBId = $userBId;
        $this->gender = $gender;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        echo 'start CalculateInteractionLike '. memory_get_usage() . "\n";
        $userArray = array();
        Compatibility::where('userAId', $this->userBId)->where('userBId', $this->userAId)->update(['interactionAB'=>0.0001]);
        $profiles = Compatibility::where('userAId', $this->userBId)->where('interactionAB', '>',0)->orderBy('compatibilityAB', 'desc')->take(4)->get(['compatibilityAB']);
        $compatible = array();
        for($i=0; $i<sizeof($profiles);$i++){
            $compatible[] = $profiles[$i]->compatibilityAB;
        }
        $std = sizeof($compatible)>1 ? $this->_calculateStd($compatible) : 0;
        $messagedProfile = Message::where('userBId', $this->userBId)->where('type', '1')->get(['userAId']);
        for($i=0;$i<sizeof($messagedProfile);$i++){
            Compatibility::where('userAId',$this->userBId)->where('userBId', $messagedProfile[$i]->userAId)->update(array('interactionAB' => $std));
        }
        $this->userAId = null;
        $this->userBId = null;
        $this->gender = null;
        $userArray = null;
        $profiles = null;
        $compatible = null;
        $std = null;
        $messagedProfile = null;

    }

    private function _calculateStd($compatible){
        return sqrt(array_sum(array_map([$this,"_stdSquare"], $compatible, array_fill(0,count($compatible), (array_sum($compatible) / count($compatible))))) / (count($compatible)-1));
    }

    private static function _stdSquare($x, $mean){
        return pow($x - $mean, 2);
    }

    public function __destruct(){
        $this->cleanup();
        echo 'end CalculateInteractionLike '. memory_get_usage() . "\n";
    }

    public function cleanup() {
        //cleanup everything from attributes
        foreach (get_class_vars(__CLASS__) as $clsVar => $_) {
            unset($this->$clsVar);
        }
    }
}

如果处理上述作业,则每次 RAM 都会增加一些。有什么想法吗?

【问题讨论】:

  • 进程启动时消耗多少内存?
  • 它不断增加并达到 190-200 MB。之后我重新启动它。
  • memory=128 表示至少在处理完一个作业后会自动重启worker。
  • 是的,没错。在看到内存达到 190-200 MB 后,我添加了 memory=128。
  • 理论上,这个类实际上在处理完作业后就被销毁了,因此清理所有变量应该不会有任何变化。我会更多地研究您在那里处理的数组和集合的大小。难道这实际上不是内存泄漏,而是元素列表上的更大尺寸?为什么不记录集合/数组的大小?另外,您能告诉我们您的操作系统版本、PHP 版本、主管版本吗?如果存在内存泄漏,则更有可能是其中一个或一个库的具体实现问题。

标签: laravel queue daemon


【解决方案1】:

作为一种解决方法 - 如果您找不到内存泄漏的来源 - 您可以直接切换到 queue:listen 而无需任何守护进程标志。

这将在每次作业后“重新启动”框架,通过 PHP 释放所有内存。

这与 Supervisor 兼容,这将确保 queue:listen 始终重新启动。

【讨论】:

    【解决方案2】:

    你没有清理内存的唯一地方是for()

            for($i=0;$i<sizeof($messagedProfile);$i++){
                Compatibility::where('userAId',$this->userBId)->where('userBId', $messagedProfile[$i]->userAId)->update(array('interactionAB' => $std));
            }
    

    第一个 where 是静态的 (::used) 但在内部创建了对象,然后您开始使用 -> 来调用函数。您是否尝试检查是否有描述符并手动调用垃圾收集器?

     for($i=0;$i<sizeof($messagedProfile);$i++){
                Compatibility::where('userAId',$this->userBId)->where('userBId', $messagedProfile[$i]->userAId)->update(array('interactionAB' => $std));
                gc_collect_cycles();
            }
    

    第二件事 where(), update() 等可以返回对对象的引用,所以如果是的话你想试试:

                for($i=0;$i<sizeof($messagedProfile);$i++){
                    $tmp = Compatibility::where('userAId',$this->userBId)->where('userBId', $messagedProfile[$i]->userAId)->update(array('interactionAB' => $std));
    $tmp = null;
                }
    

    请注意,php https://codereview.stackexchange.com/questions/57847/case-of-the-hidden-memory-leak

    【讨论】:

      猜你喜欢
      • 2011-05-06
      • 1970-01-01
      • 2015-04-16
      • 2013-12-14
      • 1970-01-01
      • 2021-01-31
      • 2015-02-22
      • 1970-01-01
      • 2018-11-12
      相关资源
      最近更新 更多