2013-08-30 8 views
12

मेरा प्रश्न कोर डेटा और स्मृति जारी नहीं किया जा रहा है। मैं एक वेब सेवा से डेटा आयात करने की एक सिंक प्रक्रिया कर रहा हूं जो एक जेसन लौटाता है। मैं स्मृति में लोड करता हूं, आयात करने के लिए डेटा, लूप के माध्यम से और NSManagedObjects बनाते हैं। आयातित डेटा को उन वस्तुओं को बनाने की आवश्यकता होती है जिनके पास अन्य वस्तुओं के संबंध होते हैं, कुल मिलाकर लगभग 11.000 होते हैं। लेकिन समस्या को अलग करने के लिए मैं अभी केवल पहले और दूसरे स्तर के आइटम बना रहा हूं, रिश्ते को छोड़कर, वे 9043 ऑब्जेक्ट्स हैं।कोर डेटा आयात - स्मृति जारी नहीं

मैंने उपयोग की गई स्मृति की मात्रा की जांच शुरू कर दी, क्योंकि ऐप प्रक्रिया के अंत में (पूर्ण डेटा सेट के साथ) क्रैश हो रहा था। पहली मेमोरी जांच जेसन की मेमोरी में लोड होने के बाद होती है, ताकि माप वास्तव में केवल निर्माण को ध्यान में रखे, और कोर डेटा में ऑब्जेक्ट्स डालें।

  • 1 लगातार स्टोर समन्वयक
  • 1 मुख्य ManagedObjectContext (एमएमसी) (NSMainQueueConcurrencyType पढ़ने के लिए प्रयोग किया जाता है: क्या मैं इस्तेमाल किया स्मृति की जाँच करने के लिए उपयोग के लिए इस कोड (source)

     
    -(void) get_free_memory { 
    
        struct task_basic_info info; 
        mach_msg_type_number_t size = sizeof(info); 
        kern_return_t kerr = task_info(mach_task_self(), 
                TASK_BASIC_INFO, 
                (task_info_t)&info, 
                &size); 
        if(kerr == KERN_SUCCESS) { 
         NSLog(@"Memory in use (in bytes): %f",(float)(info.resident_size/1024.0)/1024.0); 
        } else { 
         NSLog(@"Error with task_info(): %s", mach_error_string(kerr)); 
        } 
    } 
    

    मेरे सेटअप है (केवल पढ़ने) ऐप में डेटा)

  • 1 पृष्ठभूमि प्रबंधित ऑब्जेक्ट कॉन्टेक्स्ट (बीएमसी) (NSPrivateQueueConcurrencyType, undoManager डेटा को आयात करने के लिए उपयोग किया जाता है)

बीएमसी एमएमसी से स्वतंत्र है, इसलिए बीएमसी एमएमसी का कोई बाल संदर्भ नहीं है। और वे किसी भी मूल संदर्भ साझा नहीं करते हैं। एमएमसी में बदलावों को सूचित करने के लिए मुझे बीएमसी की जरूरत नहीं है। तो बीएमसी को केवल डेटा बनाने/अपडेट/हटाने की जरूरत है।

Plaform:

  • आईपैड 2 और 3
  • आईओएस, मैं 5.1 और 6.1 के लिए तैनाती के लक्ष्य निर्धारित करने के लिए परीक्षण किया है। डेटा आयात, इस्तेमाल किया स्मृति को बढ़ाने के लिए नहीं रुकता और iOS के निकास के लिए सक्षम होने के लिए प्रतीत नहीं होता: वहाँ कोई अंतर नहीं
  • XCode 4.6.2
  • एआरसी

समस्या है प्रक्रिया के अंत के बाद भी स्मृति। जो, डेटा नमूना बढ़ने के मामले में, मेमोरी चेतावनी और ऐप के समापन के बाद होता है।

अनुसंधान:

  1. एप्पल प्रलेखन

  2. अंक के अच्छे संक्षिप्त मन में है जब आयात करने कोर डेटा के लिए डेटा (Stackoverflow)

  3. टेस्ट मेमोरी रिलीज के परीक्षण और विश्लेषण।ऐसा लगता है कि मुझे वही समस्या है, और उसने ऐप्पल से अभी तक कोई प्रतिक्रिया नहीं के साथ एक ऐप्पल बग रिपोर्ट भेजी है। (Source)

  4. आयात और प्रदर्शित बड़े डेटा सेट (Source)

  5. डेटा की बड़ी राशि आयात करने के लिए सबसे अच्छा तरीका है यह इंगित करता है। हालांकि वह उल्लेख करता है:

    "मैं कॉलिंग -सेट के बिना एक स्थिर 3 एमबी मेमोरी में लाखों रिकॉर्ड आयात कर सकता हूं।"

    इससे मुझे लगता है कि यह किसी भी तरह से संभव हो सकता है? (Source)

टेस्ट:

डाटा नमूना: 9043 वस्तुओं के कुल निर्माण।

  • संबंधों के निर्माण बंद कर दिया, के रूप में प्रलेखन कहते हैं कि वे "महंगा"
  • नहीं प्राप्त कर रहा है किया जा रहा है कर रहे हैं

कोड:


- (void)processItems { 
    [self.context performBlock:^{ 
     for (int i=0; i < [self.downloadedRecords count];) { 
      @autoreleasepool 
      { 
       [self get_free_memory]; // prints current memory used 
       for (NSUInteger j = 0; j < batchSize && i < [self.downloadedRecords count]; j++, i++) 
       { 
        NSDictionary *record = [self.downloadedRecords objectAtIndex:i]; 

        Item *item=[self createItem]; 
        objectsCount++; 

        // fills in the item object with data from the record, no relationship creation is happening 
        [self updateItem:item WithRecord:record]; 

        // creates the subitems, fills them in with data from record, relationship creation is turned off 
        [self processSubitemsWithItem:item AndRecord:record]; 
       } 
       // Context save is done before draining the autoreleasepool, as specified in research 5) 
       [self.context save:nil]; 

       // Faulting all the created items 
       for (NSManagedObject *object in [self.context registeredObjects]) { 
        [self.context refreshObject:object mergeChanges:NO]; 
       } 
       // Double tap the previous action by reseting the context 
       [self.context reset]; 
      } 
     } 
    }]; 
    [self check_memory];// performs a repeated selector to [self get_free_memory] to view the memory after the sync 
} 

माप:

सिंक के बाद यह 28 एमबी तक पहुंचने के बाद 16.97 एमबी से 30 एमबी तक चला जाता है। प्रत्येक 5 सेकंड में get_memory कॉल को दोहराएं स्मृति को 28 एमबी पर रखता है।

किसी भी भाग्य के बिना अन्य परीक्षण:

  • लगातार दुकान पुनः बनाने के रूप में अनुसंधान 2 में किया है) कोई प्रभाव नहीं
  • जाने के लिए धागा अगर स्मृति पुनर्स्थापित करता है यह देखने के लिए थोड़ा इंतज़ार परीक्षण किया है, उदाहरण के 4 है)
  • पूरी प्रक्रिया के बाद शून्य पर संदर्भ संदर्भ
  • किसी भी बिंदु पर संदर्भ सहेजने के बिना पूरी प्रक्रिया करना (जानकारी के लिए खोना)। यह वास्तव में 20 एमबी पर छोड़कर, स्मृति की कम मात्रा को बनाए रखने के परिणाम के रूप में दिया गया। लेकिन यह अभी भी कम नहीं है और ... मुझे संग्रहीत जानकारी की आवश्यकता है :)

शायद मुझे कुछ याद आ रहा है लेकिन मैंने वास्तव में बहुत परीक्षण किया है, और दिशानिर्देशों का पालन करने के बाद मैं स्मृति को कम करने की उम्मीद करूंगा फिर। मैंने ढेर के विकास की जांच के लिए आवंटन यंत्र चलाए हैं, और यह भी ठीक लगता है। कोई स्मृति लीक भी नहीं।

मैं परीक्षण/समायोजन के लिए विचारों से बाहर निकल रहा हूं ... अगर मैं किसी और का परीक्षण कर सकता हूं, या शायद यह गलत बता रहा हूं कि मैं क्या गलत कर रहा हूं, तो मैं वास्तव में सराहना करता हूं। या यह ऐसा ही है, यह कैसे काम करना चाहिए ... जो मुझे संदेह है ...

किसी भी मदद के लिए धन्यवाद।

संपादित

मैं गतिविधि मॉनिटर टेम्पलेट और परिणाम "रियल मेमोरी उपयोग" में दिखाया गया है के साथ स्मृति के उपयोग प्रोफ़ाइल उपकरणों का इस्तेमाल किया है एक है कि get_free_memory साथ कंसोल में मुद्रित हो जाता है के रूप में ही है और स्मृति अभी भी जारी नहीं होने लगती है। बगल में पूर्ववत प्रबंधक जो भी एप्पल और बहुत महत्वपूर्ण द्वारा सिफारिश की है अक्षम करने -

+0

यह उस फ़ंक्शन के बजाय इंस्ट्रूमेंट्स में मेमोरी उपयोग का विश्लेषण करने के लिए बहुत बेहतर होगा। अलग-अलग समय में मेमोरी उपयोग दिखाने के अलावा, यह स्मृति आवंटन को कोड की विशिष्ट पंक्तियों से जोड़ देगा। –

+0

इसके अलावा, ऐसा लगता है कि आंतरिक लूप के माध्यम से प्रत्येक पास एक ही रिकॉर्ड को संसाधित करने जा रहा है, क्योंकि उस लूप के दौरान 'i' नहीं बदलता है। –

+0

हाय टॉम, आपकी प्रतिक्रिया के लिए धन्यवाद। मैंने ऐप प्रोफाइल और लीक टेम्पलेट के लिए आवंटन टेम्पलेट के साथ ऐप का प्रोफाइल किया है, सब कुछ ठीक लगता है ... क्या आप मेमोरी मॉनीटर का उपयोग करने का सुझाव देंगे? मैं उस प्रोफाइलर के साथ बहुत अनुभवी नहीं हूँ। वास्तव में 'i' दूसरे लूप में से एक द्वारा बढ़ रहा है (आपको इसे देखने के लिए स्क्रॉल करने की आवश्यकता है, कोड पूरी तरह से फ्रेम में फिट नहीं है)। ऐसा करने से, मैं '@ ऑटोरेलीजपूल 'ब्लॉक समाप्त होने से पहले बैच को बचाने में सक्षम हूं, जो एक शोध है जिसे मैंने रिसर्च 5 में पढ़ा है) –

उत्तर

10

ठीक है यह काफी शर्मनाक है ... Zombies, योजना पर सक्षम थे तर्क वे बंद कर दिया गया, लेकिन पर निदान "सक्षम ज़ोंबी वस्तुओं" जाँच कर रहा था ...

इस बंद की जा रही स्मृति स्थिर रखता है ।

उन लोगों के लिए धन्यवाद जो प्रश्न को पढ़ते हैं और इसे हल करने की कोशिश करते हैं!

+0

शर्मनाक ... लेकिन आपने मुझे निराशा के कुछ और घंटों से बचाया ... मैं पूरी तरह से भूल गया कि मैंने उन्हें सक्षम किया था और यह पता लगाने की कोशिश कर रहा था कि मेरा ऐप मेमोरी मेमोरी क्यों कर रहा था! – RyanG

+0

यहां मेरे जीवन के 9 0 मिनट बर्बाद करने के लिए धन्यवाद। – Gapp

+0

आपको एक और शर्मिंदा डेवलपर से धन्यवाद: / – Rog

2

मुझे ऐसा लगता है, कुंजी अपने पसंदीदा स्रोत का दूर ले ("3MB, रिकॉर्ड के लाखों") बैचिंग कि उल्लेख किया गया है है)।

मुझे लगता है कि यहां महत्वपूर्ण बात यह है कि इस बैचिंग को @autoreleasepool पर भी लागू होना है।

प्रत्येक 1000 पुनरावृत्तियों में ऑटोरेलीज पूल को निकालने के लिए अपर्याप्त है। आपको वास्तव में एमओसी को बचाने की जरूरत है, फिर पूल को निकालें।

अपने कोड में, दूसरे @autoreleasepool को लूप के लिए दूसरे स्थान पर डालने का प्रयास करें। फिर अपने बैच आकार को ठीक-ठीक करने के लिए समायोजित करें।

मैंने मूल आईपैड 1 पर 500,000 से अधिक रिकॉर्ड के साथ परीक्षण किए हैं। केवल JSON स्ट्रिंग का आकार 40 एमबी के करीब था। फिर भी, यह सभी दुर्घटनाओं के बिना काम करता है, और कुछ ट्यूनिंग भी स्वीकार्य गति की ओर जाता है। मेरे परीक्षणों में, मैं ऐप तक दावा कर सकता था। एक मूल आईपैड पर 70 एमबी मेमोरी।

+0

हाय मुंडी, आपकी प्रतिक्रिया के लिए धन्यवाद। यह वास्तव में एक राहत है कि आप उस रिकॉर्ड के साथ परीक्षण करने में सक्षम थे। मुझे आशा है कि मैं इसे भी प्राप्त कर सकता हूं। यदि मैंने लूप के लिए दूसरे में दूसरा '@ ऑटोरेलीजपूल' रखा है, तो पूल को निकालने के बाद, इस मामले में बचत नहीं हो रही है? असल में, मैंने आपके द्वारा उल्लिखित उद्धरण के बाद पूल को निकालने के बाद बचाने के उद्देश्य से लूप के लिए दो के साथ सेटअप किया है ... क्या यह '@ autoreleasepool' बचत को प्रभावित नहीं करेगा? –

+0

जब तक आप * @ autoreleasepool' के अंदर * सहेजते हैं, तो आपको स्मृति सुधार होना चाहिए। ध्यान दें कि आपके कोड में आप एक '@ autoreleasepool' में कई बार सहेजते हैं। – Mundi

+0

यदि मैं गलत नहीं हूं तो मैं प्रत्येक '@ autoreleasepool' में केवल एक बार सहेज रहा हूं।ध्यान दें कि लूप के लिए भीतरी बैच है (यह बाहरी लूप के सूचकांक 'i' में भी वृद्धि करता है), संदर्भ सहेजता है, पूल नालियों, और नए' @ autoreleasepool' के लिए बाहरी के अगले लूप पर बनाया जाता है और अगला बैच को संसाधित किया जा रहा है –

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