2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

再起処理がメモリ食うって本当?を検証してみた

Posted at

株式会社オズビジョンのユッコ (@terra_yucco) です。
業務内のコードレビューで久々に再帰処理を見かけました。
個人的に、再帰処理は (構文解析など、構造がそれに適したものの用途でない限り) メモリの消費が激しいので使うべきでないと教えられてきましたが、実際どうなのかを計測してみました。

TL;DR

今回の単純なコードの例では、圧倒的に普通のループのほうがよさげ。
無理に再帰を使う理由が見当たらない。

再帰処理

コード

recursion.php
<?php

$class = new Main();
$class->work();

class Main
{
    public function work()
    {
        echo memory_get_usage(true) . PHP_EOL;
        echo memory_get_usage(false) . PHP_EOL;
        echo memory_get_peak_usage(true) . PHP_EOL;
        echo memory_get_peak_usage(false) . PHP_EOL;
        $this->loop();
        echo memory_get_usage(true) . PHP_EOL;
        echo memory_get_usage(false) . PHP_EOL;
        echo memory_get_peak_usage(true) . PHP_EOL;
        echo memory_get_peak_usage(false) . PHP_EOL;
    }

    private function loop($index = 0)
    {
        if ($index >= 20000) {
           echo '$index=[' . $index . ']' . PHP_EOL;
           return;
        }
        $this->loop($index + 1);
    }
}

結果 (10 回分)

usage
true
after
usage
false
after
peak
true
after
peak
false
after
usage
true
after
usage
false
after
peak
true
after
peak
false
after
real user sys
min 262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.334s 0m0.020s 0m0.028s
max 262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.807s 0m0.060s 0m0.052s
avg 262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.516s 0m0.034s 0m0.040s
90%Tile 262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.678s 0m0.052s 0m0.048s

raw data

usage
true
after
usage
false
after
peak
true
after
peak
false
after
usage
true
after
usage
false
after
peak
true
after
peak
false
after
real user sys
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.334s 0m0.028s 0m0.040s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.590s 0m0.032s 0m0.048s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.347s 0m0.036s 0m0.036s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.531s 0m0.052s 0m0.032s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.807s 0m0.060s 0m0.048s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.413s 0m0.020s 0m0.028s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.678s 0m0.024s 0m0.048s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.470s 0m0.024s 0m0.028s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.397s 0m0.024s 0m0.040s
262144 230688 262144 238592 3145728 230712 9699328 9575632 0m0.597s 0m0.036s 0m0.052s

通常ループ処理

loop.php
<?php

$class = new Main();
$class->work();

class Main
{
    public function work()
    {
        echo memory_get_usage(true) . PHP_EOL;
        echo memory_get_usage(false) . PHP_EOL;
        echo memory_get_peak_usage(true) . PHP_EOL;
        echo memory_get_peak_usage(false) . PHP_EOL;
        $this->loop();
        echo memory_get_usage(true) . PHP_EOL;
        echo memory_get_usage(false) . PHP_EOL;
        echo memory_get_peak_usage(true) . PHP_EOL;
        echo memory_get_peak_usage(false) . PHP_EOL;
    }

    private function loop($index = 0)
    {
        while ($index < 20000) {
            $index++;
        }
        echo '$index=[' . $index . ']' . PHP_EOL;
        return;
    }
}

結果 (10 回分)

usage
true
after
usage
false
after
peak
true
after
peak
false
after
usage
true
after
usage
false
after
peak
true
after
peak
false
after
real user sys
min 262144 230432 262144 238400 262144 230432 262144 238400 0m0.115s 0m0.016s 0m0.012s
max 262144 230432 262144 238400 262144 230432 262144 238400 0m0.239s 0m0.044s 0m0.044s
avg 262144 230432 262144 238400 262144 230432 262144 238400 0m0.155s 0m0.029s 0m0.026s
90%Tile 262144 230432 262144 238400 262144 230432 262144 238400 0m0.201s 0m0.040s 0m0.036s

raw data

usage
true
after
usage
false
after
peak
true
after
peak
false
after
usage
true
after
usage
false
after
peak
true
after
peak
false
after
real user sys
262144 230432 262144 238400 262144 230432 262144 238400 0m0.166s 0m0.024s 0m0.020s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.239s 0m0.020s 0m0.028s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.201s 0m0.028s 0m0.016s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.189s 0m0.024s 0m0.012s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.115s 0m0.028s 0m0.028s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.130s 0m0.036s 0m0.036s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.117s 0m0.016s 0m0.044s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.129s 0m0.032s 0m0.032s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.134s 0m0.040s 0m0.024s
262144 230432 262144 238400 262144 230432 262144 238400 0m0.132s 0m0.044s 0m0.020s

乱暴な比較

統計サンプルとするには少ないですが、とりあえず各々 10 回ずつ実行して比較をしてみました。

再起処理 - ループ処理

ほぼ全ての項目で、再起処理の方が利用リソースが多いことがわかります。
時間については議論できるほどのオーダーではないかもしれません。

ただし memory_get_usage() 系の関数で取得しているメモリ使用量については、byte 単位とはいえかなりの差が出ています。
だいたい 9 MB くらいでしょうか。
今回の、ただ単にカウントアップした数字を出すだけのプログラムの場合には 9 MB ものメモリを使う価値はないと思いますので、素直にループ処理を書いておくのが正解と言えそうです。

usage
true
after
usage
false
after
peak
true
after
peak
false
after
usage
true
after
usage
false
after
peak
true
after
peak
false
after
real user sys
min 0 256 0 192 2883584 280 9437184 9337232 0m0.219s 0m0.004s 0m0.016s
max 0 256 0 192 2883584 280 9437184 9337232 0m0.568s 0m0.016s 0m0.008s
avg 0 256 0 192 2883584 280 9437184 9337232 0m0.361s 0m0.005s 0m0.014s
90%Tile 0 256 0 192 2883584 280 9437184 9337232 0m0.477s 0m0.012s 0m0.012s

Conclusion

前職の頃、念仏のように聞いていた「再起処理はメモリを食うぞ」を簡易的にですが確認してみました。
業務で見かけたコードはもっとずっと複雑なので、そういうコードで比較ができればもう少し面白い結果になるかもしれません。

良い記事や知見があれば、ぜひ教えていただきたいです!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?