2

私のプロジェクトでは、db テーブルをツリーとして使用するために NestedSetBehavior モデル拡張を使用しています。

私は例を書きます:

    $model = SiteMap()->findAll();
    $log .= $this->debug_memory('used')."<br>";
    $ancestors = null;
    foreach ($model as $item) {
        $ancestors = $item->ancestors()->findAll();
    }
    $log .= $this->debug_memory('used')."<br>";
    echo $log;

(debug_memory ソースはフレンドリーな memory_get_usage() を返すだけで、$model には 50 個のアイテムがあります)

結果は次のとおりです。

used: 10525440
used: 15892712

簡単な計算の後、メモリ使用量は 5,24 Mb に増加しました。

しかし、私は $item->ancestors()->findAll(); を使わなければなりません。サイクルで何度も、私のメモリは 138 Mb に増加しました。@out of memory エラーが発生します".

unset() を使用してみます:

    $model = SiteMap()->findAll();
    $log .= $this->debug_memory('used')."<br>";
    $ancestors = null;
    foreach ($model as $item) {
       $ancestors= $item->ancestors()->findAll();
    }
    $ancestors = null;
    unset($ancestors);
    $log .= $this->debug_memory('used')."<br>";
    echo $log;

しかし、私は結果を得る鋼:

used: 10525984
used: 15893320

動作祖先関数のソースは次のとおりです。

public function ancestors($depth=null)
{
    $owner=$this->getOwner();
    $db=$owner->getDbConnection();
    $criteria=$owner->getDbCriteria();
    $alias=$db->quoteColumnName($owner->getTableAlias());

    $criteria->mergeWith(array(
        'condition'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute).'<'.$owner->{$this->leftAttribute}.
            ' AND '.$alias.'.'.$db->quoteColumnName($this->rightAttribute).'>'.$owner->{$this->rightAttribute},
        'order'=>$alias.'.'.$db->quoteColumnName($this->leftAttribute),
    ));

    if($depth!==null)
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->levelAttribute).'>='.($owner->{$this->levelAttribute}-$depth));

    if($this->hasManyRoots)
    {
        $criteria->addCondition($alias.'.'.$db->quoteColumnName($this->rootAttribute).'='.CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount);
        $criteria->params[CDbCriteria::PARAM_PREFIX.CDbCriteria::$paramCount++]=$owner->{$this->rootAttribute};
    }

    return $owner;
}

それで、私の質問は、なぜこの関数が非常に多くのメモリを使用するのか、変数メモリを設定解除するとクリーニングされないのはなぜですか?

4

2 に答える 2

4

ファイルのログをコメントアウトしprotected/config/main.phpます。(または、構成設定を定義する場所。)

表示されているのは、すべてのログが各 Active Record 呼び出しで書き込まれた結果である可能性が高く、オブジェクトの設定を解除してもメモリが解放されない理由を説明できます。使用されているメモリはモデルではなく、ログにあります。

それを試して、結果を報告してください。

于 2012-12-01T18:08:47.657 に答える
1

答え

ログを無効にして(@ willem-renzemaがすでに述べたように)メモリを使用しないようにすることは常に良いことです(特にリークをテストしている場合)。

ただし、サンプル コードの各祖先を呼び出しdetachBehaviors()て、メモリ リークを防止する必要があります。unsetメモリ リークの発生を防ぐために、ビヘイビアを使用する前に、アタッチされたビヘイビアを持つすべてのオブジェクト インスタンスに対してこれを行うことをお勧めします。オブジェクトを明示的に「設定解除」していない場合でも(たとえば、変数がスコープ外に移動しています)。

NestedSetBehavior でのこの問題の詳細については、https://github.com/yiiext/nested-set-behavior/issues/25を参照してください。

PHP と Yii でのメモリ リークと循環参照に関するより一般的な議論については、https://github.com/yiisoft/yii/issues/1329#issuecomment-18729026も参照してください。


ノート

デストラクタ ( __destruct()) を使用して、動作のデタッチを処理したくなるかもしれません。ただし、この特定のケースでは、ここで言及されているデストラクタ ルールのために機能しません

「オブジェクトは、すべての参照が設定されていない__destruct()場合にのみリソースを解放し、メソッドをトリガーし ます。それらがオブジェクト内にある場合でも...ため息!」- (nox at オレゴンドットで, 2009).

unsetNestedSetBehavior には、次の名前の静的配列に格納されている「祖先」インスタンスへの参照がまだあるため、「祖先」を使用するだけでは、このルールは満たされません$_cached。この参照は、NestedSetBehavior インスタンス自体を破棄することによってのみクリアされます。これはdetachBehaviors()、ビヘイビアーの「所有者」オブジェクトを呼び出した場合に発生します。

于 2014-06-10T14:08:25.093 に答える