2012-03-14 25 views
43

असल में मुझे symfony2 और doctrine2 के संयोजन के साथ बहुत परेशानी है। मुझे विशाल डेटासेट (लगभग 2-3 मिलियन लिखना और पढ़ना) से निपटना होगा और स्मृति से बाहर निकलने से बचने के लिए बहुत सारे प्रयास करना होगा।मेमोरी लीक सिम्फनी 2 सिद्धांत 2/स्मृति सीमा से अधिक

2 मुख्य बिंदु बाहर figgured, कि "रिसाव" ing स्मृति (वे वास्तव में नहीं वास्तव में लीक कर रहे हैं, लेकिन आवंटन एक बहुत)

  1. Entitymanager इकाई भंडारण (मुझे नहीं इस का असली नाम पता एक) ऐसा लगता है जैसे कि यह सब कार्रवाई की entites रहता है और आप

    $entityManager->clear()
  2. सिद्धांत QueryCache के साथ इस भंडारण नियमित रूप से साफ़ करने के लिए है - यह सब इस्तेमाल किया प्रश्नों कैश और केवल विन्यास मैंने पाया था कि तुम क्या तय करने में सक्षम हैं कैश की तरह आप हमें चाहते हैं ई। मुझे एक वैश्विक अक्षम नहीं मिला और न ही प्रत्येक क्वेरी को अक्षम करने के लिए एक उपयोगी ध्वज मिला। तो आम तौर पर समारोह के साथ हर क्वेरी ऑब्जेक्ट के लिए इसे अक्षम

     
    $qb = $repository->createQueryBuilder($a); 
    $query = $qb->getQuery(); 
    $query->useQueryCache(false); 
    $query->execute(); 
    

तो .. सब मैं अभी पता लगा thats .. मेरे प्रश्न हैं:

वहाँ एक आसान तरीका अस्वीकार करने के लिए है Entitymanagerstorage से कुछ वस्तुओं? क्या इकाई प्रबंधक में क्वेरी कैश उपयोग सेट करने का कोई तरीका है? क्या मैं इस कैशिंग व्यवहार को सिम्फनी सिद्धांत सिद्धांत में कभी भी कॉन्फ़िगर कर सकता हूं? अगर कुछ एक .. मेरे लिए कुछ अच्छा सुझाव दिए गए है अन्यथा इस सकता है कुछ रूकी मदद की

बहुत बढ़िया नहीं होगा ..

cya

+2

डी 2 ओआरएम परत वास्तव में बड़े पैमाने पर बैच प्रोसेसिंग के लिए डिज़ाइन नहीं किया गया है। आप डीबीएएल परत का उपयोग करके बेहतर हो सकते हैं और केवल सरणी के साथ काम कर सकते हैं। – Cerad

+1

** के साथ चल रहा है - नो-डीबग ** बहुत मदद करता है (डीबग मोड में प्रोफाइलर स्मृति में प्रत्येक क्वेरी के बारे में जानकारी बरकरार रखता है) – arnaud576875

उत्तर

83

एक छोटी सी देर हो गई, लेकिन मुझे लगता है मैं सिर्फ एक thread on Google Groups पाया है बेंजामिन Eberlei से है कि आपके सवाल का जवाब: के रूप में डिफ़ॉल्ट SQL कनेक्शन के प्रवेश द्वारा Doctrine Configuration Reference ने कहा, kernel.debug के मान पर सेट है, इसलिए यदि आप डिबग सच SQL कमांड के लिए सेट के साथ AppKernel instantiated है प्रत्येक ite के लिए स्मृति में संग्रहीत हो जाओ राशन।

आप या तो झूठी को AppKernel का दृष्टांत चाहिए, प्रवेश करनेको गलत आप में config YML सेट करें, या तो का उपयोग कर EntityManager

$em->getConnection()->getConfiguration()->setSQLLogger(null); 
+4

ब्रावो! हम महीनों के लिए इस समस्या के खिलाफ अपने सिर मार रहे हैं! – jsalvata

+3

यह एसएफ 2 के साथ बात है। आप ** वास्तव में ** यह समझने के लिए दस्तावेज़ों और कोड को पढ़ने की आवश्यकता है कि यह कैसे काम करता है। दूसरे दिन हमने पाया कि हम अनुरोधों के बीच डीक्यूएल और मेटाडेटा को कैश नहीं कर रहे थे। हमने ऐसा किया और [समाप्त हुआ] (https://coderwall.com/p/ry1y0a) परिवर्तन – Sergi

+4

परिवर्तन से पहले दो बार अनुरोध के साथ यह बहुत उपयोगी था। मेरे पास एक कंसोल कमांड था जो मैंने लिखा था (एक "डेमन" टाइप कमांड की तरह था) जो स्मृति से बाहर चल रहा था और ऑब्जेक्ट मैनेजर पर 'स्पष्ट()' विधि का उपयोग करना पर्याप्त नहीं था। इस एसक्यूएल लॉगर को अक्षम करने से चाल चल रही थी। हालांकि, चूंकि मैं कंसोल कमांड में था, इसलिए मुझे यह करने के लिए वास्तव में इकाई प्रबंधक को प्राप्त करने के लिए '$ this-> getContainer() -> get ('doctrine') -> getEntityManager()' का उपयोग करना पड़ा। – jzimmerman2011

17

अपने आदेश चलाने की कोशिश करें इससे पहले कि अशक्त करने के लिए मैन्युअल रूप से SQLLogger सेट --no-debug के साथ। डीबग मोड में प्रोफाइलर स्मृति में प्रत्येक प्रश्न के बारे में जानकारी बरकरार रखता है।

+0

धन्यवाद यह स्क्लॉगिंग को बंद करने के संयोजन में वास्तव में – Chausser

+0

में मदद मिली, इसने टेम्पलेट इंजन और टहनी के साथ एक समस्या हल की। एक साधारण टेम्पलेट पर एक लूप चलाना विकास में स्मृति_लीक दिखाई दिया। – fyrye

+0

जब मुझे यह पता चला तो मैं घंटों तक टंकण कर रहा था ... इससे समस्या हल हो गई। धन्यवाद :) – indriq

3

सिद्धांत डेवलपर्स से ही कुछ "अजीब" समाचार सिम्फोनी बर्लिन में रहते हैं पर मिला - वे कहते हैं, कि बड़े बैच पर, हमें एक ORM उपयोग नहीं करना चाहिए .. यह OOP

में इस तरह सामान के निर्माण के लिए अभी कोई कारगर है

.. हाँ .. शायद वे सही हैं xD

+0

हमें शायद उस सड़क पर भी जाना होगा .... यह बेकार है कि भले ही वे इसके बारे में जानते हों, इसे संबोधित नहीं किया जा रहा है –

0

मौजूद किसी भी डॉक्टर कैश को अक्षम करने का प्रयास करें। (यदि आप एपीसी/अन्य को कैश के रूप में उपयोग नहीं कर रहे हैं तो स्मृति का उपयोग किया जाता है)।

निकालें क्वेरी कैश

$qb = $repository->createQueryBuilder($a); 
$query = $qb->getQuery(); 
$query->useQueryCache(false); 
$query->useResultCache(false); 
$query->execute(); 

लिए विश्व स्तर पर अक्षम करें यह

इसके अलावा इस खाली करने के लिए है कि (here से) मदद कर सकता है

$connection = $em->getCurrentConnection(); 
$tables = $connection->getTables(); 
foreach ($tables as $table) { 
    $table->clear(); 
} 
3

एक विकल्प है कोई तरीका नहीं है मानक सिद्धांत 2 दस्तावेज के अनुसार, आपको इसकी आवश्यकता होगी मैन्युअल रूप से स्पष्ट या अलग इकाइयों।

इसके अलावा, जब प्रोफाइलिंग सक्षम है (डिफ़ॉल्ट देव वातावरण में)। Symfony2 में DoctrineBundle कई लॉगर्स को बहुत मेमोरी का उपयोग करने में कॉन्फ़िगर करता है। आप पूरी तरह से लॉगिंग अक्षम कर सकते हैं, लेकिन इसकी आवश्यकता नहीं है।

एक दिलचस्प साइड इफेक्ट, लॉगर्स दोनों डॉक्टर ओआरएम और डीबीएएल को प्रभावित करते हैं। लॉगर्स में से एक के परिणामस्वरूप डिफ़ॉल्ट लॉगर सेवा का उपयोग करने वाली किसी भी सेवा के लिए अतिरिक्त मेमोरी उपयोग होगा। इन सभी को अक्षम करना आदेशों में आदर्श होगा - क्योंकि अभी तक प्रोफाइलर का उपयोग नहीं किया जाता है।

यहाँ आप जबकि रूपरेखा रखने Symfony2 के अन्य भागों में सक्षम स्मृति तीव्र वालों को निष्क्रिय करने के लिए क्या कर सकते है:

$c = $this->getContainer(); 
/* 
* The default dbalLogger is configured to keep "stopwatch" events for every query executed 
* the only way to disable this, as of Symfony 2.3, Doctrine Bundle 1.2, is to reinistiate the class 
*/ 

$dbalLoggerClass = $c->getParameter('doctrine.dbal.logger.class'); 
$dbalLogger = new $dbalLoggerClass($c->get('logger')); 
$c->set('doctrine.dbal.logger', $dbalLogger); 

// sometimes you need to configure doctrine to use the newly logger manually, like this 
$doctrineConfiguration = $c->get('doctrine')->getManager()->getConnection()->getConfiguration(); 
$doctrineConfiguration->setSQLLogger($dbalLogger); 

/* 
* If profiling is enabled, this service will store every query in an array 
* fortunately, this is configurable with a property "enabled" 
*/ 
if($c->has('doctrine.dbal.logger.profiling.default')) 
{ 
    $c->get('doctrine.dbal.logger.profiling.default')->enabled = false; 
} 

/* 
* When profiling is enabled, the Monolog bundle configures a DebugHandler that 
* will store every log messgae in memory. 
* 
* As of Monolog 1.6, to remove/disable this logger: we have to pop all the handlers 
* and then push them back on (in the correct order) 
*/ 
$handlers = array(); 
try 
{ 
    while($handler = $logger->popHandler()) 
    { 
     if($handler instanceOf \Symfony\Bridge\Monolog\Handler\DebugHandler) 
     { 
      continue; 
     } 
     array_unshift($handlers, $handler); 
    } 
} 
catch(\LogicException $e) 
{ 
    /* 
    * As of Monolog 1.6, there is no way to know if there's a handler 
    * available to pop off except for the \LogicException that's thrown. 
    */ 
    if($e->getMessage() != 'You tried to pop from an empty handler stack.') 
    { 
     /* 
     * this probably doesn't matter, and will probably break in the future 
     * this is here for the sake of people not knowing what they're doing 
     * so than an unknown exception is not silently discarded. 
     */ 

     // remove at your own risk 
     throw $e; 
    } 
} 

// push the handlers back on 
foreach($handlers as $handler) 
{ 
    $logger->pushHandler($handler); 
} 
9
  1. सेट एसक्यूएल लकड़हारा शून्य पर

$em->getConnection()->getConfiguration()->setSQLLogger(null);

  1. मैन्युअल रूप सेके बाद मैन्युअल रूप से कॉल करें 0

$em->clear(); gc_collect_cycles();

1 को zend.enable_gc निर्धारित करते हैं, या मैन्युअल रूप से उपयोग करने से पहले gc_enable() कॉल करने के लिए मत भूलना gc_collect_cycles()

  1. --no-debug विकल्प जोड़ें अगर आप से आदेश चला कंसोल।
9

1. app/config/config.yml

doctrine: 
    dbal: 
     driver: ... 
     ... 
     logging: false 
     profiling: false 

में या कोड में

$this->em->getConnection()->getConfiguration()->setSQLLogger(null); 

2. सेना कचरा कलेक्टर प्रवेश और रूपरेखा को बंद। यदि आप सक्रिय रूप से सीपीयू का उपयोग करते हैं तो कचरा कलेक्टर इंतजार कर रहा है और आप जल्द ही बिना किसी स्मृति के अपने आप को पा सकते हैं।

पहले मैन्युअल कचरा संग्रहण प्रबंधन सक्षम करें। कोड में कहीं भी gc_enable() चलाएं। फिर कचरा कलेक्टर को मजबूर करने के लिए gc_collect_cycles() चलाएं।

उदाहरण

public function execute(InputInterface $input, OutputInterface $output) 
{ 
    gc_enable(); 

    // I'm initing $this->em in __construct using DependencyInjection 
    $customers = $this->em->getRepository('AppBundle:Customer')->findAll(); 

    $counter = 0; 
    foreach ($customers as $customer) { 
     // process customer - some logic here, $this->em->persist and so on 

     if (++$counter % 100 == 0) { 
      $this->em->flush(); // save unsaved changes 
      $this->em->clear(); // clear doctrine managed entities 
      gc_collect_cycles(); // PHP garbage collect 

      // Note that $this->em->clear() detaches all managed entities, 
      // may be you need some; reinit them here 
     } 
    } 

    // don't forget to flush in the end 
    $this->em->flush(); 
    $this->em->clear(); 
    gc_collect_cycles(); 
} 

यदि आपका तालिका बहुत बड़ा है, findAll प्रयोग नहीं करते। इटरेटर का उपयोग करें - http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/batch-processing.html#iterating-results

0

मैंने बैच प्रोसेसिंग here के लिए सिद्धांत के साथ सिम्फनी कंसोल कमांड का उपयोग करने के लिए युक्तियों का एक गुच्छा पोस्ट किया है।

संबंधित मुद्दे