4

大量の(巨大な)データを管理(エクスポート)する必要があるphpアプリケーションがあり、本番環境で実行する必要があります...したがって、メモリ使用量をできるだけ少なくする必要があります(主な基準)。

次のように、アプリがサイクルでデータをエクスポートすると簡単に言います

for($fileCounter=0;$fileCounter<=70;$fileCounter++) {
... HERE a lot of (more than 1K lines) huge work, many variables a lot of DB queries from another databases etc ...
}

他の人にとっては時間がかかる可能性があるため、ここで完全なロジックを示したくはありません。ここでは要点ではありません。

主なポイントは、unset()各反復中にすべての新しく作成された変数を使用すると、メモリ使用量が減少しないのはなぜですか? このような

for($fileCounter=0;$fileCounter<=70;$fileCounter++) {
    // optimization purpose
    $vars_at_start = array_keys(get_defined_vars());
    echo memory_get_peak_usage(true) . PHP_EOL;

... huge logic ...

    $vars_at_end = array_diff($vars_at_start, array_keys(get_defined_vars()));
    foreach($vars_at_end as $v) unset($v);
    unset($vars_at_end);
}

どうすればメモリ使用量を減らすことができますか? 非常に多くのクエリ、変数などを使用する必要がある場合..

PSコードは私のものではありません:)そして、ゼロから書き直したくありません。最適化の方向性を探しているだけです。

変数を使用しない場合、次はメモリ使用量をクリーニングします(各反復の最初に測定しています)

23592960

Started: 0 - 12:58:26
Ended: 13:00:51
877920256 (difference 854'327'296)

Started: 1 - 13:00:51
Ended: 13:03:39
1559494656 (difference 681'574'400)

と変数のクリーニング

23592960

Started: 0 - 12:47:57
Ended: 12:50:20
877920256 (difference 854'327'296)

Started: 1 - 12:50:20
Ended: 12:53:16
1559756800 (difference 681'836'544)

私の読書に基づいて、PHPにはメモリをリークする多くの理由があります...このようにhttps://bugs.php.net/bug.php?id=48781

それが役立つvalgrindと呼ばれるツールがあります。それを試してみてください:)

4

6 に答える 6

3

unset() は、PHP プロセスによって消費されたメモリを解放しませんが、PHP スクリプト自体が使用できるように解放します。

したがって、ループ内で 10M のサイズの変数を 10 回作成し、ループの最後でそれを設定解除 (または再書き込み) する場合、ループの最後までのメモリ消費は 10M + 他のすべての変数と同じくらい低くなるはずです。 .

大きくなった場合は、表示したくない完全なロジックのどこかにリークがあります。

于 2013-01-15T11:13:03.980 に答える
0
$vars_at_end = array_diff($vars_at_start, array_keys(get_defined_vars()));
foreach($vars_at_end as $v) unset($v);
unset($vars_at_end);

このコードブロック全体が変数のコピー(またはコピーのコピー)で機能しているため、大量のメモリが追加されます。設定を解除するのは、foreachループ内のコピーのコピーだけです。

使用する実際の変数の設定を解除する必要があります

于 2013-01-15T11:35:42.397 に答える
0

ところで、あなたの foreach ... unset ループはとにかく何もしません。PHP は、参照ベースの遅延コピーオン書き込みシステムを使用して、メモリの使用を最適化します。この foreach ループは、実質的にノーオペレーションです。ストレージは解放されます -- これは内部の Zend エンジンの emalloc アロケータ ( OS ではなく) に返されます -- または要素の参照カウントがゼロになると再利用されます。これは、関数のスコープを離れるときのローカル変数と、クラス オブジェクトを破棄するときのクラス プロパティに対して発生します。変数の浅いコピーを複製してからこれを設定解除しても意味がありません。これは参照カウントで +1 -1 を行うだけだからです。

ループで使用される主要な変数のコードをマイニングして設定を解除すると、参照カウントが完全に減少して 0 になり、再利用のためにストレージが解放されます。しかし、troelskyn が暗示しているように、既存のコードがゼロ以外の参照を持つデータ要素を残す方法はたくさんあります。古典的な方法は、コードが参照を使用している場合、循環が明示的に中断されない限り、再利用されない循環参照チェーンを作成できることです。結果を保持するために使用されるグローバル配列があっても、メモリを占有する可能性があります。

申し訳ありませんが、あなたの声明:

他の人にとっては時間がかかる可能性があるため、ここで完全なロジックを示したくはありません。ここでは要点ではありません。

間違っている。PHP でストレージをメモリ プールに返さない理由を理解したい場合は、コードを調べる必要があります。

于 2013-01-15T16:10:47.003 に答える
0

PHPが自動的にそれを行うからです。
変数が使用されなくなると、PHP 自体が設定を解除します。

于 2013-01-15T11:09:53.010 に答える
0

unsetメモリを解放しないためです。変数を解放するだけです。しかし、その変数がある種の複雑な構造を指している場合、その PHP のメモリ管理は解放する方法を理解できません。

于 2013-01-15T11:13:59.427 に答える