7

मैं एक आईपैड एप्लिकेशन पर काम करता हूं जिसमें सिंक प्रक्रिया होती है जो वेब सेवाओं और कोर डेटा को एक तंग लूप में उपयोग करती है। Apple's Recomendation के अनुसार स्मृति पदचिह्न को कम करने के लिए मैं आवधिक रूप से NSAutoreleasePool आवंटित और निकालें। यह वर्तमान में बहुत अच्छा काम करता है और वर्तमान एप्लिकेशन के साथ कोई स्मृति समस्या नहीं है। हालांकि, मैं एआरसी में जाने की योजना बना रहा हूं जहां NSAutoreleasePool अब मान्य नहीं है और इस तरह के प्रदर्शन को बनाए रखना चाहते हैं। मैंने कुछ उदाहरण बनाए और उन्हें समय दिया और मुझे आश्चर्य है कि एआरसी का उपयोग करके, एक ही तरह के प्रदर्शन को स्वीकार करने और कोड पठनीयता को बनाए रखने के लिए सबसे अच्छा तरीका क्या है@autoreleasepool के साथ पीक मेमोरी उपयोग को कम करें

परीक्षण उद्देश्यों के लिए मैं 3 परिदृश्यों के साथ आया, प्रत्येक 1 और 10,000,000 के बीच एक संख्या का उपयोग कर एक स्ट्रिंग बनाते हैं। मैंने ऐप्पल एलएलवीएम 3.0 कंपाइलर (डब्ल्यू/ओ जीडीबी-ओ 0) और एक्सकोड 4.2 के साथ मैक 64 बिट एप्लिकेशन का उपयोग करके कितना समय लगाया, यह निर्धारित करने के लिए मैंने प्रत्येक उदाहरण को 3 बार चलाया। मैंने स्मृति के माध्यम से मोटे तौर पर क्या देखा, यह देखने के लिए उपकरणों के माध्यम से प्रत्येक उदाहरण भी चलाया।

उदाहरण नीचे निम्नलिखित कोड ब्लॉक के भीतर समाहित कर रहे हैं के प्रत्येक:

int main (int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSDate *now = [NSDate date]; 

     //Code Example ... 

     NSTimeInterval interval = [now timeIntervalSinceNow]; 
     printf("Duration: %f\n", interval); 
    } 
} 

NSAutoreleasePool बैच [मूल पूर्व एआरसी] (पीक मेमोरी: ~ 116 KB)

static const NSUInteger BATCH_SIZE = 1500; 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
    { 
     NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
     [text class]; 

     if((count + 1) % BATCH_SIZE == 0) 
     { 
      [pool drain]; 
      pool = [[NSAutoreleasePool alloc] init]; 
     } 
    } 
    [pool drain]; 

रन टाइम्स:
10,928158
10,912849
11,084716


बाहरी @autoreleasepool (पीक मेमोरी: ~ 382 एमबी)

@autoreleasepool { 
     for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 

भागो टाइम्स:
11,489350
11,310462
11,344662


इनर @autoreleasepool (पीक मेमोरी: ~ 61.2KB)

for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
    { 
     @autoreleasepool { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 

भागो टाइम्स:
14.031112
14.284014
14।099625


डब्ल्यू @autoreleasepool/गोटो (पीक मेमोरी: ~ 115kb)

static const NSUInteger BATCH_SIZE = 1500; 
    uint32_t count = 0; 

    next_batch: 
    @autoreleasepool { 
     for(;count < MAX_ALLOCATIONS; count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
      if((count + 1) % BATCH_SIZE == 0) 
      { 
       count++; //Increment count manually 
       goto next_batch; 
      } 
     } 
    } 

भागो टाइम्स:
10,908756
10,960189
11,018382

goto बयान निकटतम प्रदर्शन की पेशकश की, लेकिन यह एक goto उपयोग करता है। कोई विचार?

अद्यतन:

नोट: goto बयान के रूप में documentation में कहा गया है और स्मृति लीक नहीं होगा एक @autoreleasepool के लिए एक सामान्य निकास है।

प्रवेश पर, एक ऑटोरेलीज पूल धक्का दिया जाता है। सामान्य निकास पर (ब्रेक, रिटर्न, गोटो, फॉल-थ्रू, और इसी तरह) ऑटोरेलीज पूल पॉप हो गया है। मौजूदा कोड के साथ संगतता के लिए, अगर बाहर निकलने के कारण बाहर निकलें, ऑटोरेलीज पूल पॉप नहीं किया गया है।

+1

अनुकूलक का उपयोग करें। एआरसी कोड के लिए यह महत्वपूर्ण है। –

+0

ताकि 'गोटो' निश्चित रूप से नहीं है, मुझे नहीं पता, मेमोरी रिसाव का कारण बन रहा है? बाकी सब कुछ समझ में आता है: कम draining तेजी से है। वैसे भी, मैं केवल पठनीयता पर टिप्पणी कर सकता हूं: कहीं भी आप पूल ठीक है। उस गले को पीले चिपचिपा नोट की आवश्यकता होगी। –

+0

गोटो किसी भी स्मृति को रिसाव नहीं लग रहा था। ऐसा लगता है कि स्कोप ने ऑटोरेलीज पूल को निकाला था जैसा कि मैंने उम्मीद की थी लेकिन मैं एआरसी (अभी तक) पर कोई विशेषज्ञ नहीं हूं और यूबी पर भरोसा नहीं करना चाहता हूं। – Joe

उत्तर

9

निम्नलिखित goto बिना goto जवाब के रूप में भी वही करता है चाहिए:

for (NSUInteger count = 0; count < MAX_ALLOCATIONS;) 
{ 
    @autoreleasepool 
    { 
     for (NSUInteger j = 0; j < BATCH_SIZE && count < MAX_ALLOCATIONS; j++, count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 
} 
+0

धन्यवाद, लंबा दिन, सरल पर्याप्त जवाब :)। – Joe

+1

इसे और अधिक वोट दिया जाना चाहिए क्योंकि यह वही व्यवहार करने का समाधान है जो मैन्युअल रूप से पुरानी 'एनएसएयूटोरिलीजूल' के साथ निकालने के लिए है! – mattjgalloway

2

ध्यान दें कि एआरसी महत्वपूर्ण अनुकूलन जो -O0 में सक्षम नहीं हैं सक्षम बनाता है। यदि आप एआरसी के तहत प्रदर्शन को मापने जा रहे हैं, तो आप को ऑप्टिमाइज़ेशन सक्षम के साथ परीक्षण करना चाहिए। अन्यथा, आप एआरसी के "बेवकूफ मोड" के खिलाफ अपने हाथ से ट्यून किए गए रखरखाव/रिलीज प्लेसमेंट को मापेंगे।

अनुकूलन के साथ अपने परीक्षण फिर से चलाएं और देखें कि क्या होता है।

अद्यतन: मैं उत्सुक था, इसलिए मैंने इसे स्वयं चलाया। ये 7,000,000 आवंटन के साथ रिलीज मोड (-ओएस) में रनटाइम परिणाम हैं।

arc-perf[43645:f803] outer: 8.1259 
arc-perf[43645:f803] outer: 8.2089 
arc-perf[43645:f803] outer: 9.1104 

arc-perf[43645:f803] inner: 8.4817 
arc-perf[43645:f803] inner: 8.3687 
arc-perf[43645:f803] inner: 8.5470 

arc-perf[43645:f803] withGoto: 7.6133 
arc-perf[43645:f803] withGoto: 7.7465 
arc-perf[43645:f803] withGoto: 7.7007 

arc-perf[43645:f803] non-ARC: 7.3443 
arc-perf[43645:f803] non-ARC: 7.3188 
arc-perf[43645:f803] non-ARC: 7.3098 

और स्मृति चोटियों (केवल 100,000 आवंटन के साथ चलाने क्योंकि उपकरण हमेशा के लिए ले रहा था):

Outer: 2.55 MB 
Inner: 723 KB 
withGoto: ~747 KB 
Non-ARC: ~748 KB 

इन परिणामों मुझे एक छोटे से आश्चर्य। खैर, स्मृति शिखर परिणाम नहीं करते हैं; यह वही है जो आप उम्मीद करेंगे। लेकिन inner और withGoto के बीच रन टाइम अंतर, ऑप्टिमाइज़ेशन सक्षम होने के साथ भी, जो मैं अनुमान लगाता हूं उससे अधिक है।

बेशक, यह कुछ पैथोलॉजिकल माइक्रो-टेस्ट है, जो कि किसी भी एप्लिकेशन के असली दुनिया के प्रदर्शन को मॉडल करने की संभावना नहीं है। यहां ले लिया गया है कि एआरसी वास्तव में कुछ ओवरहेड हो सकता है, लेकिन आपको धारणा बनाने से पहले हमेशा अपने वास्तविक आवेदन को मापना चाहिए।

(इसके अलावा, मैं @ ipmcc के जवाब छोरों के लिए नेस्टेड का उपयोग कर परीक्षण किया गया है, यह लगभग ठीक goto संस्करण की तरह व्यवहार किया।)

+0

धन्यवाद, टिप की सराहना करते हैं। पता नहीं था कि अतिरिक्त कदम उठाए गए थे लेकिन तब से पूर्ण बनाते हैं। क्या http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html के समान कोई अनुकूलन मार्गदर्शिका है? सटीक झंडे खोजने की उम्मीद नहीं है, लेकिन किस प्रकार के अनुकूलन हो सकते हैं इसके साथ-साथ। मुझे कुछ उपयोगी विशेषता वस्तुएं मिलीं [यहां] (http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization) लेकिन ऐसा लगता है कि यह संकलक अनुकूलन निर्भर नहीं है। – Joe

+0

मैंने ऑप्टिमाइज़ेशन सक्षम के साथ कुछ वास्तविक-दुनिया परीक्षण जोड़ा। –

+0

अनुकूलन के साथ आंकड़ों की जांच में आपकी सहायता के लिए धन्यवाद। विभिन्न उद्देश्यों के लिए भविष्य में किस विधि का उपयोग करना है, यह तय करने के लिए यह उपयोगी होगा (आईपीएमसीसी के उत्तर के लिए 'गोटो' धन्यवाद को छोड़कर)। उम्मीद है कि कुछ और लोग आते हैं और ऊपर आते हैं। – Joe

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