昨日までこれが問題だとは思いませんでした。
昨夜、私はこの機能を実装するための 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();
上記の例では、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 でリソースを積極的に解放する必要はありません」と書かれている場合は、それを焼くことをお勧めします。