Magento-Kunde speichert Speicherverlust

7

Ich versuche, Kundendaten in großen Mengen zu bearbeiten (ein paar tausend Datensätze), und Magento verfügt immer noch nicht über genügend verfügbaren Speicher, um das Skript auszuführen.

Nach einigen Tests mit memory_get_usage()dem Täter scheint dies die $customer->save()Methode zu sein, die 5 MB Speicher für jede Speicherung benötigt, diese aber nicht freigibt, wenn sie abgeschlossen ist.

Wenn Sie ein paar tausend Datensätze durchlaufen, wird daher nicht genügend Speicher ausgeführt.

Folgendes habe ich bisher versucht:

$customer->clearInstance()

unset($customer)

Dies scheint jedoch nicht zu helfen.

Unten ist mein Code:

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
}

Jede Hilfe wäre sehr dankbar.

ps Ich bin mir nicht sicher, ob die clearInstance()Funktion (im Mage_Core_Model_Abstract) irgendetwas tut. Wenn jemand einen Einblick in diese Funktion hat, wäre es sehr dankbar, wenn sie geteilt würde :)

pzirkind
quelle
Welche Version von Magento verwenden Sie?
Jesseconnr
Magento CE 1.7.0.2, aber auch auf Magento EE testen das gleiche Problem
pzirkind
1
Anstelle der als Antworten bereitgestellten Problemumgehungen ist es möglicherweise möglich, den tatsächlichen Speicherverlust zu ermitteln, wenn Sie Zeit haben. Bitte beachten Sie die beiden Artikel, die ich zur Verfügung stelle. Der erste kann Ihnen helfen, das Problem aufzuspüren, der zweite erklärt einen Fehler in PHP selbst. Möglicherweise ist das gleiche Problem in Magento vorhanden. stackoverflow.com/questions/849549/… paul-m-jones.com/archives/262
jesseconnr
Welche PHP-Version benutzt du?
Flyingmana
@Flyingmana 5.4.17 auf Dev Machine und 5.3 auf Produktion
Pzirkind

Antworten:

3

Ich denke, dass dies mit einem Kernproblem von PHP zusammenhängt, das ohne umfangreiche Änderungen an den Magento-Kerndateien nicht einfach zu lösen ist.

Die einzige Möglichkeit, dies zu erreichen, ist die Verwendung einer Problemumgehung:

Ich schlage vor:

ein. Wenn dies vom Browser aus aufgerufen wird, würde ich einen separaten Ajax-Aufruf durchführen, wie @Julien Lacal in seiner Antwort empfohlen hat.

b. Wenn dies alles serverseitig erledigt wird, würde ich dies in zwei Skripte createCustomerAddressaufteilen , wobei 1. eines die vorhandene Kundenliste durchläuft und 2. eines die Funktion mithilfe von Post-Parametern aufruft. Das zweite Skript sollte dann mit CURL aus dem ersten Skript aufgerufen werden, damit jede Instanz des zweiten Skripts isoliert ausgeführt wird und nicht vom Speicherverlust betroffen ist.

josephtikva
quelle
5

Der Speicher wird erst freigegeben, wenn keine Verweise auf diese Variable / dieses Objekt vorhanden sind. Ich vermute - und werde meine Antwort nach Bestätigung bearbeiten, dass das Ereignissystem in Magento eine Instanz des Modells an den Beobachter weitergibt und daher im Speicher ein Verweis darauf vorhanden ist.

Dies ist jedoch ein gut dokumentiertes Problem. (eine, die ich 2011 kommentiert habe http://www.magentocommerce.com/boards/viewthread/26561/ ).

josephtikva
quelle
Auf jeden Fall sinnvoll, aber der Beobachter sollte es irgendwann
freigeben
afaik findet der standard PHP Garbage Collector KEINE Kreise, daher kann es sein, dass wenn Sie einen Kunden und eine Adresse haben, beide Objekte nicht freigegeben werden - nur eine Idee, danke für die Antwort Joseph!
Fabian Blechschmidt
Klingt plausibel - auf den ersten Blick scheint nur das Newsletter-Modul das Ereignis zum Speichern des Kunden zu beobachten. @pzirkind sehen Sie den gleichen Speicherverbrauch bei vollständig deaktivierter Newsletter-Erweiterung?
Kristof bei Fooman
@Fooman ja es scheint den gleichen Speicherverbrauch zu haben, wenn das Newsletter-Modul deaktiviert ist (via xml)
pzirkind
4

Ich glaube, dies ist ein bekanntes Problem auf allen Plattformen und Versionen von Magento. unset()oder clearInstance()wird keine Wirkung haben. Mage::getModel()Speicherverlust in allen Fällen, auf die ich gestoßen bin (Kunden, Produkte, Bestellungen usw.). Der einzige Weg, den ich gefunden habe, besteht darin, wenn möglich eine Sammlung zu verwenden (möglicherweise nicht für Sie zutreffend), wenn Sie mit einer großen Anzahl von Objekterstellungen arbeiten. Wenn Ihr Vorgang abgeschlossen ist, wird der Speicher freigegeben.

Haben Sie nicht mehr genügend Speicher? Dies ist normalerweise kein Problem, es sei denn, Sie sind es. Wenn Ihnen möglicherweise der Arbeitsspeicher ausgeht, können Sie versuchen, den Massenprozess in separate Läufe in Ihrer Erweiterung aufzuteilen. Wenn dies in einem Shell-Skript enthalten ist, ist es einfach, es aufzubrechen. Erstellen Sie einfach zwei oder mehr Dateien und führen Sie sie nacheinander mit vordefinierten Kundenbereichen aus entity_id.

musicliftsme
quelle
Vielen Dank für die Informationen, die sich mit der Verwendung von Sammlungen
befassen. Ich habe
Ich habe versucht, eine Sammlung mit $ collection-> save () zu speichern und habe anscheinend den gleichen Speicherverlust. Gibt es einen Code, den Sie posten können, um den Unterschied im Speicher zu erkennen?
pzirkind
2

Eine gute Problemumgehung wäre, ein eigenes Administrationsmodul für den Massenkundenimport zu erstellen und Ajax-Aufrufe an einen Controller zu verwenden, um Daten in kleineren Gruppen zu importieren. Auf diese Weise wird Ihnen nicht der Arbeitsspeicher ausgehen, da bei jedem Ajax-Aufruf ein neuer Prozess gestartet wird, anstatt aufgrund desMage::getModel('customer/address')

Julien Lachal
quelle
Das ist eine interessante Problemumgehung (+1 für die Idee), aber ich möchte etwas konsistenteres für das Backend
pzirkind
1

Scheint, als hätte ich beim Anrufen einen großen Speicherverlust festgestellt Model::save()

Nachdem das Element in der Datenbank gespeichert wurde, gibt es den folgenden Code in der genannten Methode:

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

Auf diese Weise wird das Modell dem statischen Parameter hinzugefügt $_commitCallbacks. Die Methode wird entfernt, wenn die Transaktionsebene nur auf Null gesetzt ist.

Um dies zu lösen, fügen Sie Ihrem eigenen Ressourcenmodell entweder den folgenden Code hinzu:

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

Dies funktioniert nur für einen Ressourcentyp. Sie müssen dies für alle Ressourcenmodelle tun, die in Ihrer Schleife häufig aktualisiert werden. Ein Nachteil ist, dass die Methode afterCommitCallback()Ihres Modells niemals aufgerufen wird.

Eine andere (bessere) Möglichkeit besteht darin, die Methoden und zu überschreiben commit()und rollback()das Modell in jedem Fall aus der Variablen zu entfernen.

Mikrofone
quelle