Magentoのお客様がメモリリークを保存


7

私は顧客データを一括で編集しようとしています(数千レコード)。Magentoはスクリプトを実行するために利用可能なメモリを使い果たし続けています。

memory_get_usage()犯人とのいくつかのテストの後、$customer->save()保存ごとに5Mのメモリを使用するように見える方法のようですが、完了時に解放しません。

その結果、数千のレコードをループするときに、メモリが不足しています。

これが私がこれまでに試したことです:

$customer->clearInstance()

unset($customer)

これは助けにはならないようです。

以下は私のコードです:

public function createCustomerAddress($customerAddressData, $email){
     $customer = Mage::getModel('customer/customer');

     $customer->setWebsiteId(Mage::app()->getWebsite()->getId());
     $customer->loadByEmail($email);

     $address   = Mage::getModel('customer/address');

     $address->addData($customerAddressData);
     $customer->addAddress($address);
     unset($address);
     try{
         $customer->save();
     }catch (Exception $e){
         var_dump($customerAddressData);
         var_dump($e->getMessage());
     }
    echo "\n" . "Before unsetting \n" . memory_get_usage() . "\n";
    $customer->clearInstance();
    unset($customer);
    echo "\n" . "After  \n" . memory_get_usage() . "\n";  // no difference than before
}

どんな助けでも大歓迎です。

ps clearInstance()(Mage_Core_Model_Abstract内の)関数が何かを実行するかどうかはわかりません。誰かがこれについて何らかの洞察を持っている場合、共有されていれば非常にありがたいです:)


Magentoのどのバージョンを使用していますか?
jesseconnr 14年

Magento CE 1.7.0.2、ただしMagento EEでのテストも同じ問題
pzirkind

1
回答として提供される回避策の代わりに、時間があれば、実際のメモリリークを追跡できる可能性があります。私が提供する2つの記事をご覧ください。1つ目は問題の追跡に役立ち、2つ目はPHP自体のバグを説明します。同じ問題がMagentoにも存在する可能性があります。 stackoverflow.com/questions/849549/…paul-m-jones.com/archives/262
jesseconnr

どのphpバージョンを使用していますか?
Flyingmana 2014年

@Flyingmana 5.4.17(開発マシン)および5.3(本番)
pzirkind

回答:


3

これは、PHPのコアの問題に関連していると思います。これは、コアのMagentoファイルを大幅に変更しないと簡単に解決できません。

これを行う唯一の方法は回避策を使用することです:

私が提案する:

a。これがブラウザから呼び出されている場合は、@ Julien Lacalが彼の回答で推奨しているように、別のajax呼び出しを行います。

b。これがすべてサーバー側で行われている場合、これを2つのスクリプトに分解します。1つは既存の顧客リストを反復するもの、2 createCustomerAddress。ポストパラメータを使用して関数を呼び出すものです。2番目のスクリプトは、最初のスクリプトのCURLを使用して呼び出す必要があります。これにより、2番目のスクリプトの各インスタンスは独立して実行され、メモリリークの影響を受けません。


5

メモリは、その変数/オブジェクトへの参照がない場合にのみ解放されます。私は疑っています-確認したら私の回答を編集します。Magentoのイベントシステムはモデルのインスタンスをオブザーバーに渡すため、メモリ内に参照があります。

しかし、これは十分に文書化された問題です。(2011年に私がコメントしたものhttp://www.magentocommerce.com/boards/viewthread/26561/)。


確かに観察者がいくつかの点で、それを解放する必要がありますが、理にかなって
pzirkind

afaikは標準のphpガベージコレクターがサークルを見つけられないため、顧客と住所がある場合、両方のオブジェクトが解放されない可能性があります-アイデア、回答ジョセフに感謝!
Fabian Blechschmidt 2014年

もっともらしい-一見、ニュースレターモジュールだけが顧客の保存イベントを監視しているようです。@pzirkindニュースレター拡張機能を完全に無効にしても、同じメモリ消費が見られますか?
クリストフ、フーマンで2014年

@Foomanはい、ニュースレターモジュールが無効にされた場合(xmlを介して)と同じメモリ消費量のようです
pzirkind

4

これは、Magentoのすべてのプラットフォームとバージョンにわたる既知の問題であると思います。unset()またはclearInstance()何の効果もありません。Mage::getModel()私が遭遇したすべてのインスタンス(顧客、製品、注文など)でメモリがリークしました。私が見つけた唯一の回避策は、多数のオブジェクト作成を処理するときに、可能であれば(適用できない場合があります)代わりにコレクションを使用することです。プロセスが完了すると、メモリが解放されます。

メモリが不足していますか?あなたがそうでない限り、これは通常問題ではありません。メモリが不足している場合は、拡張機能でバルクプロセスを個別の実行に分割しようとすることができます。これがシェルスクリプト内にある場合は、簡単に分割できます。2つ以上のファイルを作成し、定義済みの顧客entity_idの範囲で次々に実行します。


情報のおかげで、このためのコレクションの使用を検討しますが、モデルのリークに利用できる修正の種類があるかどうか疑問に思いました
pzirkind

$ collection-> save()を使用してコレクションを保存しようとしましたが、同じメモリリークがあるようです。メモリの違いを確認できる場所に投稿できるコードはありますか?
pzirkind 2014年

2

良い回避策は、顧客の一括インポート用に独自の管理モジュールを構築し、コントローラーへのAjax呼び出しを使用して、より小さなセットでデータをインポートすることです。この方法では、Ajax呼び出しを行うたびに新しいプロセスが起動されるため、メモリ不足になることがありません。Mage::getModel('customer/address')


これは興味深い回避策(アイデアの+1)ですが、バックエンドでより一貫したものを求めています
pzirkind

1

呼び出し時に大きなメモリリークを見つけたようです Model::save()

アイテムがデータベースに保存された後、前述のメソッドに次のコードがあります。

$this->_getResource()->addCommitCallback(array($this, 'afterCommitCallback'))

このようにして、モデルは静的パラメーターに追加されます$_commitCallbacks。トランザクションレベルがゼロにのみ設定されている場合、メソッドは削除されます。

これを解決するには、次のコードを独自のリソースモデルに追加します。

public function addCommitCallback($callback)
{
    return $this;
    //return parent::addCommitCallback($callback);
}

これは1つのタイプのリソースモデルに対してのみ機能します。ループで頻繁に更新されるすべてのリソースモデルに対してこれを行う必要があります。欠点はafterCommitCallback()、モデルのメソッドが呼び出されないことです。

別の(より良い)可能性はcommit()rollback()メソッドとメソッドを上書きし、すべてのケースで変数からモデルを削除することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.