12

その場でPNG画像を作成してブラウザに送信するPHPクラスがあります。PHP マニュアルには、メモリを解放するためにimagedestroy関数が最後に呼び出されることを確認する必要があると書かれています。クラスを使用していなければ、次のようなコードになります。

function shutdown_func() 
{
    global $img;
    if ($img)
        imagedestroy($img);
}
register_shutdown_function("shutdown_func");

ただし、私のクラスの適切な場所は、クラスのデストラクタでimagedestroyを呼び出すことだと思います。

デストラクタがシャットダウン関数と同じように呼び出されるかどうかを確認できませんでしたか? たとえば、ユーザーがブラウザの STOP ボタンを押したときに実行が停止した場合。

注: 回答に何を書いても、それをサポートする記事またはマニュアル ページ (URL) を参照してください。

4

4 に答える 4

14

PHPをApacheモジュールとして使用して、Apacheでテストしました。次のような無限ループを作成しました。

<?php
class X
{
    function __destruct()
    {
        $fp = fopen("/var/www/htdocs/dtor.txt", "w+");
        fputs($fp, "Destroyed\n");
        fclose($fp);
    }
};

$obj = new X();
while (true) {
    // do nothing
}
?>

これが私が見つけたものです:

  • Firefox で STOP ボタンを押しても、このスクリプトは停止しません。
  • Apache をシャットダウンすると、デストラクタが呼び出されない
  • PHP max_execution_time に達すると停止し、デスタクタは呼び出されません

ただし、これを行う:

<?php
function shutdown_func() {
    $fp = fopen("/var/www/htdocs/dtor.txt", "w+");
    fputs($fp, "Destroyed2\n");
    fclose($fp);
}
register_shutdown_function("shutdown_func");

while (true) {
    // do nothing
}
?>

shutdown_func が呼び出されます。したがって、これは、クラス デスタクタがシャットダウン関数ほど優れていないことを意味します。

于 2008-10-25T18:47:11.970 に答える
2

始めたことを終わらせるべきだという原則に基づいて、デストラクタは無料通話の正しい場所だと思います。

オブジェクトが破棄されるとデストラクタが呼び出されますが、スクリプトの実行が終了するまでシャットダウン関数は呼び出されません。Wolfieが指摘したように、サーバーまたはスクリプトを強制的に停止した場合、これらは必ずしも発生しませんが、その時点で、PHPによって割り当てられたメモリはとにかく解放されます。

また、Wolfieは、スクリプトが閉じたときにPHPがスクリプトリソースを解放するため、これらのオブジェクトの1つだけをインスタンス化する場合は、大きな違いに気付かないでしょう。ただし、後でこれらをインスタンス化する場合、またはループでインスタンス化する場合は、メモリ使用量の突然の急増について心配する必要はないでしょう。将来の健全性のために、私は元の推奨事項; デストラクタに入れます。

于 2008-10-25T23:25:11.037 に答える
1

サーバーでタイムアウトが発生し、エラーログにクラスデータを含めたい場合に特に破壊を処理しようとしていたため、最近これに問題がありました。&$this を参照するとエラーが発生します (いくつかの例で見たことがありますが、おそらくバージョンの問題または symfony の副作用です)。

class MyClass
{
    protected $myVar;

    /**
     * constructor, registers shutdown handling
     */
    public function __construct()
    {
        $this->myVar = array();

        // workaround: set $self because $this fails
        $self = $this;
        // register for error logging in case of timeout
        $shutdown = function () use (&$self) {
            $self->shutdown();
        };
        register_shutdown_function($shutdown);
    }

    /**
     * handle shutdown events
     */
    public function shutdown()
    {
        $error = error_get_last();
        // if shutdown in error
        if ($error['type'] === E_ERROR) {
            // write contents to error log
            error_log('MyClass->myVar on shutdown' . json_encode($this->myVar), 0);
        }
    }

    ...

これが誰かを助けることを願っています!

于 2015-07-29T02:24:17.440 に答える
0

あなたが見逃している大きなことの 1 つは、スクリプトの実行中に PHP が割り当てたすべてのメモリが、スクリプトが終了すると解放されることです。ユーザーが停止ボタンを押しても、PHP はスクリプトが終了するまで処理し、それを HTTP デーモンに戻して訪問者に提供します (デーモンがどれほど賢いかによって異なります)。

そのため、スクリプトの実行の最後にメモリを明示的に解放するのは少し冗長です。それは良いことだと主張する人もいるかもしれませんが、それでも冗長です。

ただし、クラス デストラクタのトピックでは、明示的に、unset()またはスクリプトの完了/終了時に、オブジェクトが破棄されるたびに呼び出されます。

画像操作で使用されるメモリを明示的に解放する開発者の推奨事項は、ビットマップが物事のメモリ側に負担をかける可能性があるため、メモリ リークが発生しないようにすることです (高さ * 幅 * ビット深度 * 3 (+アルファチャンネルがある場合は 1))

ウィキペディアのニーズを満たすには:

于 2008-10-25T18:28:37.123 に答える