2010-01-19 20 views
16

Mam problemy z wsadowym wstawieniem obiektów do bazy danych przy użyciu symfony 1.4 i doktryny 1.2.wyciek pamięci php/symfony/doctrine?

Mój model ma pewien rodzaj obiektu o nazwie "Sektor", z których każdy ma kilka obiektów typu "Cupo" (zwykle od 50 do 200000). Te obiekty są dość małe; tylko krótki ciąg identyfikacyjny i jedna lub dwie liczby całkowite. Ilekroć grupa Sektorów jest tworzona przez użytkownika, muszę automatycznie dodać wszystkie te wystąpienia "Cupo" do bazy danych. W przypadku, gdy coś pójdzie nie tak, używam operacji doktryny, aby wycofać wszystko. Problem polega na tym, że mogę utworzyć tylko około 2000 instancji, zanim phpowi zabraknie pamięci. Obecnie ma limit 128 MB, co powinno wystarczyć do obsługi obiektów, które używają mniej niż 100 bajtów. Próbowałem zwiększyć limit pamięci do 512 MB, ale php nadal zawiesza się i to nie rozwiązuje problemu. Czy poprawnie wstawiam partię lub czy jest lepszy sposób?

Oto błąd:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 71 bytes) in /Users/yo/Sites/grifoo/lib/vendor/symfony/lib/log/sfVarLogger.class.php on line 170 

A oto kod:

public function save($conn=null){ 

    $conn=$conn?$conn:Doctrine_Manager::connection(); 

    $conn->beginTransaction(); 


    try { 
     $evento=$this->object; 


     foreach($evento->getSectores() as $s){ 

      for($j=0;$j<$s->getCapacity();$j++){ 

       $cupo=new Cupo(); 
       $cupo->setActivo($s->getActivo()); 
       $cupo->setEventoId($s->getEventoId()); 
       $cupo->setNombre($j); 
       $cupo->setSector($s); 

       $cupo->save(); 

      } 
     } 

     $conn->commit(); 
     return; 
    } 
    catch (Exception $e) { 
     $conn->rollback(); 
     throw $e; 
    } 

Znów ten kod działa poprawnie na mniej niż 1000 obiektów, ale nic nie większy niż 1500. Dzięki za pomoc.

+1

oznaczyć czyjąś odpowiedź jako poprawną, prawda? – develop7

+0

W przypadku wkładek luzem możesz również rozważyć wykonanie surowej wstawki SQL za pośrednictwem PDO, zdecydowanie szybciej i nie spowoduje to przecieku pamięci. –

Odpowiedz

1

Po każdym zapisaniu spróbuj unset($cupo);. To powinno pomóc. Inną rzeczą jest podzielenie skryptu i wykonanie przetwarzania wsadowego.

1

spróbować złamać odwołanie cykliczne, które zwykle powodują wycieki pamięci z

$cupo->save(); 

$cupo->free(); //this call 

jak described w instrukcji doktryny.

0

Okresowo zamknij i ponownie otwórz połączenie - nie wiesz, dlaczego, ale wydaje się, że PDO zachowuje referencje.

3

właśnie zrobił "daemonized" skrypt z symfony 1.4 i ustawiając następujące zatrzymał pamięć wyginanie:

sfConfig::set('sf_debug', false); 
+0

To działało dla mnie, jeśli zrobisz to przed utworzeniem menedżera bazy danych. Jeśli masz jakieś zadanie, myślę, że to jest bezpieczne. –

33

Wypróbowywany robi

$cupo->save(); 
$cupo->free(); 
$cupo = null; 

(podstawiając mój kod) I jestem wciąż dostaję przepełnienia pamięci. Jakieś inne pomysły, SO?

Aktualizacja:

stworzyłem nowego środowiska w moim databases.yml, który wygląda tak:

all: 
    doctrine: 
    class: sfDoctrineDatabase 
    param: 
     dsn: 'mysql:host=localhost;dbname=.......' 
     username: ..... 
     password: ..... 
     profiler: false 

profiler: fałszywy pozycja wyłącza rejestrowanie zapytań doktryny, które zwykle prowadzi kopię każdego zapytania, które tworzysz. Nie zatrzymało to przecieku pamięci, ale udało mi się uzyskać dwa razy więcej niż importowanie danych, tak jak ja bez niego.

Aktualizacja 2

dodałem

Doctrine_Manager::connection()->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true); 

przed uruchomieniem moje zapytania i zmienił

$cupo = null; 

do

unset($cupo); 

A teraz mój scenariusz szczęśliwie ucieka. Jestem prawie pewien, że skończy się bez kończącej się pamięci RAM.

Aktualizacja 3

Tak. To zwycięska kombinacja.

+1

Mam podobny problem. Próbowałem tych rzeczy i moje działanie znacznie się poprawiło. –

+0

Jeśli to możliwe, uaktualnij do wersji php5.3 i użyj -> free(). Wycieki pamięci są powodowane przez moduł do zbierania śmieci PHP5.2, który nie może usunąć odwołań cyklicznych, które nie są już przywoływane poza ich pętlą. PHP5.3 ma lepszy kolekcjoner, a free() próbuje cofnąć te odniesienia przed zmienną opuszczającą zakres. –

+1

@Jordan - WOW miałem podobny problem - ale na select - profiler: false miał OGROMNY wpływ ... dzięki – ManseUK

2

Doktryna przecieka i niewiele można z tym zrobić. Upewnij się, że używasz $ q-> free(), gdy tylko chcesz, aby zminimalizować efekt. Doctrine nie jest przeznaczona do skryptów konserwacyjnych. Jedynym sposobem obejścia tego problemu jest złamanie skryptu na części, które wykonają część zadania. Jednym ze sposobów na to jest dodanie parametru start do skryptu i po przetworzeniu pewnej liczby obiektów, skrypt przekierowuje do siebie z wyższą wartością początkową. To działa dobrze, chociaż sprawia, że ​​pisanie skryptów konserwacyjnych jest bardziej uciążliwe.

+0

Zrobiłem to samo, co te małe sztuczki, które tak naprawdę nie pomagają. Podkreśliłem podobne podejście do twojego: http://stackoverflow.com/a/11474869/620410 – Tapper

0

co działa dla mnie jest wywołanie metody free tak:

$cupo->save(); 
$cupo->free(true); // free also the related components 
unset($cupo); 
3

dla zadania symfony, ja też do czynienia z tym problemem i sporządzono następujące rzeczy. To zadziałało dla mnie.

  • Wyłącz tryb debugowania. Dodaj następujący przed podłączeniem db zainicjować bezpłatny atrybut

    sfConfig::set('sf_debug', false); 
    
  • Set auto obiektu zapytania do połączenia db

    $connection->setAttribute(Doctrine_Core::ATTR_AUTO_FREE_QUERY_OBJECTS, true); 
    
  • darmo przez cały obiekt po użyciu

    $object_name->free() 
    
  • Usuń wszystkie tablice po użyciu unset($array_name)

  • Che ck wszystkie zapytania dotyczące doktryn użyte w zadaniu. Uwolnij wszystkie zapytania po użyciu. $q->free() (To jest dobra praktyka dla każdej chwili korzystania z zapytania.)

To wszystko. Mam nadzieję, że może komuś pomóc.

1

Dla mnie, właśnie zainicjowana zadanie tak:

// initialize the database connection 
$databaseManager = new sfDatabaseManager($this->configuration); 
$connection = $databaseManager->getDatabase($options['connection'])->getConnection(); 
$config = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod', true); 
sfContext::createInstance($config); 

(Z PROD config)
i używać za darmo() po udanej() na obiekcie doktryny

pamięci jest stabilny w 25Mo

memory_get_usage=26.884071350098Mo 

z PHP 5.3 na Debianie squeeze