我正在try 编写一个laravel函数,该函数从一个数据库获取大量记录(100,000+),然后将其放入另一个数据库.为此,我需要查询我的数据库并查看该用户是否已经存在.我反复调用这个代码:

$users = User::where('id', '=', 2)->first();

然后,在这种情况发生几百次之后,我的记忆就耗尽了.所以,我做了一个极简主义的例子,它使用了所有可用的内存,看起来是这样的:

<?php

use Illuminate\Console\Command;

class memoryleak extends Command
{
    protected $name = 'command:memoryleak';
    protected $description = 'Demonstrates memory leak.';

    public function fire()
    {
        ini_set("memory_limit","12M");

        for ($i = 0; $i < 100000; $i++)
        {
            var_dump(memory_get_usage());
            $this->external_function();
        }
    }

    function external_function()
    {
        // Next line causes memory leak - comment out to compare to normal behavior
        $users = User::where('id', '=', 2)->first();

        unset($users);
        // User goes out of scope at the end of this function
    }
}

这个脚本的输出(由'php artisan command:memoryleak'执行)如下所示:

int(9298696)
int(9299816)
int(9300936)
int(9302048)
int(9303224)
int(9304368)
....
int(10927344)
int(10928432)
int(10929560)
int(10930664)
int(10931752)
int(10932832)
int(10933936)
int(10935072)
int(10936184)
int(10937320)
....
int(12181872)
int(12182992)
int(12184080)
int(12185192)
int(12186312)
int(12187424)
PHP Fatal error:  Allowed memory size of 12582912 bytes exhausted (tried to allocate 89 bytes) in /Volumes/Mac OS/www/test/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 275

If I comment out the line "$users = User::where('id', '=', 2)->first();" then the memory usage stays stable.

Does anyone have any insight as to why this line would use memory like this, or know a smarter way to accomplish what I am trying to do?

谢谢你抽出时间.

推荐答案

I recreated your script and stepped through it with a debugger because I couldn't fathom what sort of horrible thing would cause this type of memory issue. As I stepped through, I came across this:

// in Illuminate\Database\Connection
$this->queryLog[] = compact('query', 'bindings', 'time');

似乎您在Laravel中运行的每个查询都存储在一个持久日志(log)中,这解释了您在每次查询后不断增加的内存使用量.紧靠其上的是下面一行:

if ( ! $this->loggingQueries) return;

A little more digging determined that the loggingQueries property is set to true by default, and can be changed via the disableQueryLog method, so that means, if you call:

 DB::connection()->disableQueryLog();

before you're going to execute all your queries, you won't see ever increasing memory usage; it solved the problem when I ran my test based on your example code. When you're done, if you don't want to affect the rest of the application you could call

DB::connection()->enableQueryLog();

to renable logging.

Laravel相关问答推荐

将 ID 传递给资源控制器进行编辑

如何正确使用 Spatie\Laravel Data 来获取数据?

如何使用动态翻译键翻译 Laravel硬编码字符串(还有 1 个错误)..(验证异常类)

Laravel 连接表

基于数据表 Laravel 4 导出 CSV 或 PDF

Laravel - 将变量从中间件传递到控制器/路由

Mockery 和 Laravel 构造函数注入

Laravel - 排序的集合输出不是数组

Laravel 5.3 - 将多个文件附加到 Mailables

为什么我的 Laravel 队列作业(job)在 60 秒后失败?

Twilio 查找 API 不起作用?

在 Laravel 4 迁移中创建 MYSQL 过程

在 Laravel Eloquent 中,limit 与 take 有什么区别?

laravel 5.4 指定的key太长,为什么数字191

Eloquent - 更新集合中的所有模型

Laravel:方法[显示]不存在

Laravel 4:将什么作为参数传递给 Url 类?

Laravel Eloquent模型如何从关系表中获取数据

如何判断是否在laravel中使用了分页

如果在 Laravel 5.1 中找不到路由,则显示 404 页面