19

あるデータベースから大量のレコード (100,000 以上) を取得し、それを別のデータベースに配置する laravel 関数を作成しようとしています。そのためには、データベースにクエリを実行して、ユーザーが既に存在するかどうかを確認する必要があります。このコードを繰り返し呼び出します。

$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

「$users = User::where('id', '=', 2)->first();」という行をコメントアウトすると、その後、メモリ使用量は安定したままです。

なぜこの行がこのようにメモリを使用するのか、または私がやろうとしていることを達成するためのよりスマートな方法を知っている人はいますか?

お時間をいただきありがとうございます。

4

2 に答える 2