ホームページ  >  記事  >  php教程  >  PHPer はリソースを手動で解放してください

PHPer はリソースを手動で解放してください

WBOY
WBOYオリジナル
2016-06-21 08:51:23907ブラウズ

昨日までこれが問題だとは思いませんでした。

昨夜、私はこの機能を実装するための RFC を提出しました。その出発点は非常に簡単でした。なぜなら、私は議論を見ただけで、誰かがそれを理解していなかった、と言いました。それで気づきました。

それをメールグループに送った後、開発チームの同級生であるニキータ・ポポフ(nikic)がこのRFCに強い反対を表明しました。もちろん、私たちがオンラインで議論したとき、彼は最初の議論について多くのことを言いました。彼の意見を述べた:

"リクエストが完了すると、PHP はすべてのリソースを解放します。そのため、リソースを解放するために fclose または mysql_close を呼び出す必要はありません。PHP が代わりにそれを実行します。"

そして彼は、fclose は C 関数ファミリーを継承するためだけに存在すると考えており、決して fclose を呼び出すことはないと言いました。

驚いたし、同じことを思っている人がどれだけいるのか分からなかったので、この記事を書くことにしました

PHP5.2以前のPHPではリソース管理に参照カウントを使用していましたが、zvalの参照カウントが0の場合は解放されますが、この設計はWebスクリプトを開発する場合には問題ありません。 Web スクリプトの特性と目的は実行時間が短く、長時間実行されないためです。循環参照によるリソース リークはリクエストの最後に解放されます。部分的な救済措置(バックアップ)。

ただし、PHP を使用する人が増えるにつれて、多くの人が一部のバックグラウンド スクリプトで PHP を使用するようになりました。これらのスクリプトは、循環参照があると長時間実行され、未使用のリソースを時間内に解放できなくなるという特徴があります。 、その後、これ スクリプトは最終的にメモリが不足して終了します。

そこで、PHP5.3以降、ユーザーが解決できない問題を解決するためにGCを導入しました。

これは歴史です。ここで最初の問題に戻りましょう。PHP はリクエストが完了した後にすべてのリソースを解放するため、手動で解放する必要はありません。 >

例を見てみましょう:

Mysql 最大接続数 (mysql.max_connections)

$db = mysql_connect() ; $resut = mysql_query();
// 処理結果...
usleep(500);

//mysql_close($db); たとえば、これを呼び出していないとしましょう

// 他のロジック、コストが 5 秒であると仮定します
スリープ(5);

exit(0); //終了

上記の例では、Mysql との接続を 5 秒間維持します。このようなスクリプトは一般的なアプリケーションには関係ありませんが、リクエスト量が多いスクリプトの場合、致命的な問題が発生します。

たとえば、ビジーなアプリケーションは 1 秒あたり 1,000 件のユーザーからのリクエストを処理する必要があります。5 秒間で何件のリクエストを行うことができますか? MySQL には最大接続数 (mysql.max_connections) があり、この数が一般的です。 2000 を超えないでください。デフォルトはこれより低くなります: (mysql.max_connections),

このコードにより、アプリケーションは正常にサービスを提供できなくなります。また、Mysql の処理が完了した後に接続を閉じれば、この問題は発生しません。

実際には、より現実的な問題が発生しました。次の例を見てください:

$mmc = new Memcached();

$mysql = mysql_connect();

//処理 mysql_close($mysql);
$mmc->close();



これは実際の教訓です。コードは、ある日突然、Mysql に問題が発生し、Mysql への接続に時間がかかりすぎました。最後に、接続数が多すぎると Memcache が失敗しました。

したがって、接続コストが最も高いリソースを最初に初期化する必要があります。

システム最大ハンドル (/proc/sys/fs/file-max)

これは非常に簡単です。ハンドルを解放せずにオープンし続けると、プロセスの最大ハンドル数にも制限がかかる可能性があります (ulimit -n)。 > システムコールが高い (システムコールが高い)

リクエストの完了後に PHP がすべてのリソースとメモリを正しく解放する理由は、スクリプトで新しいメモリを使用するときに、PHP が OS から大きなメモリ (ZEND_MM_SEG_SIZE サイズ) を申請し、それを A に割り当てるためです。必要なものに適した小さなメモリ。

この小さなメモリを使用しない場合、PHP はそれを OS に返さず、後続の処理のために保持します

malloc(3) によってシステム コール (brk(2)) が発生することがわかっています (もちろん mmap の可能性もあります。中国語のおかげで、ここでは詳細は考慮しません)。システム コールは高価です。

したがって、リソースの使用を終了し、期限内に解放しなかった場合、後続のロジックがメモリを要求すると、PHP は以前に要求した大きなメモリ ブロックが分割されたことを認識し、リソースへの malloc 呼び出しを行う必要があります。新しい大容量メモリを取得するには、OS が再度必要になります。また、この大容量メモリのマーキングも必要になります。

そして、リソースの使用を終了して時間内に解放すると、次回スクリプトがメモリを適用するときに、以前に返されたメモリ ブロックが再利用できるようになり、スクリプト全体が OS で一度だけメモリを適用するだけで済む可能性があります。 >

メモリのピーク使用量

これは上記と一定の関係があります。リソースの使用が終了すると、リソースは解放され、その後そのリソースを使用すると、PHP のメモリ使用量は次のようになります。

リソース+1 -> リソース-1 -> リソース-1 (ピーク値は 1)

そして、PHP リクエストが完了するまで待ってからリリースする場合:

リソース + 1 -> リソース + 1 …. -> リソース -1 (ピーク値は 2)

言い換えれば、よく書かれたスクリプトは、下手に書かれたスクリプトよりもピーク時のメモリを大幅に節約できる可能性があります。

たとえば、非常にビジーなサーバーの場合、10 個の PHP プロセスがあり、各 PHP プロセスの最大メモリは 1G で、サーバーには 8G しかメモリがありません。

結論

結論は明らかです。最初に述べたように、私はこれが問題だとは思っていませんでした。

ここで一言言わせてください。PHP の本を購入して、「PHP が自動的にリソースを解放してくれるため、PHP でリソースを積極的に解放する必要はありません」と書かれている場合は、それを焼くことをお勧めします。



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。