2009-09-05 26 views
13

मैं अपने आवेदन के विभिन्न निर्माण के साथ कुछ समय खेल रहा हूं और ऐसा लगता है कि अजीब चीजें होती हैं:कोको 64 बिट बाइनरी रिसाव स्मृति? (एनएसडीटा जारी करने से स्मृति मुक्त नहीं होता है)

मेरे ऐप में 5 एमबी निष्क्रिय पदचिह्न है। फ़ाइल के आकार में फ़ाइल मेमोरी अपलोड करते समय आरक्षित है। अपलोड के बाद आरक्षित स्मृति मुक्त होनी चाहिए। अब निर्माण में अंतर हैं (जीसी = कचरा कलेक्टर):

  • 32 बिट i386 नो-जीसी: सभी मेमोरी तुरंत मुक्त हो जाती है।
  • 32 बिट i386 जीसी: लगभग सभी स्मृति तुरंत मुक्त हो जाती है। बाकी कुछ समय बाद।
  • 64 बिट x86_64 नो-जीसी: न्यूनतम स्मृति मुक्त हो जाती है। जैसे 10%
  • 64 बिट x86_64 जीसी: बिल्कुल कोई स्मृति मुक्त नहीं है। स्मृति घंटों तक आरक्षित रहता है। (गतिविधि सोम)

मैं CLANG के साथ एलएलवीएम का उपयोग कर रहा हूं। मैं हर समय उपकरणों को चला रहा हूं और लीक/लाश/आदि की जांच कर रहा था। और सबकुछ साफ दिखता है। (ऐप अपेक्षाकृत सरल है।)

क्या इस व्यवहार के लिए कोई स्पष्टीकरण है?


अद्यतन:

कुछ अजीब सामान है कि। मैंने इस समस्या को उबलाया है:

मैं एक एनएसडीटा में 20 एमबी फ़ाइल लोड करता हूं और इसे छोड़ देता हूं। मैं बिना किसी कचरा संग्रह सक्षम कर रहा हूं। कोड है:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigshit"]; 
[bla release]; 

जब मैं i386 32 बिट के लिए 20 एमबी आवंटित और रिलीज़ किया जाता हूं। जब मैं बिल्ड को 64 बिट x86_64 पर स्विच करता हूं तो रिलीज़ कुछ भी नहीं करता है। 20 एमबी आवंटित किया गया।

upper pic 32bit lower 64 http://kttns.org/zguxn

सिवाय इसके कि ऊपरी एक 32 बिट के लिए बनाया गया है दो क्षुधा के बीच कोई अंतर और कम एक 64 बिट है। कोई जीसी चल रहा है। (जीसी के साथ एक ही समस्या दिखाई देता है सक्षम होना चाहिए।)


अद्यतन 2:

वही व्यवहार मनाया जा सकता है जब मैं केवल applicationDidFinishLaunching में ऊपरी कोड के साथ शुरू से एक नई कोको ऐप बनाने :. 64 बिट मोड में स्मृति जारी नहीं है। i386 अपेक्षित काम करता है।

एनएसडीटा के बजाय एनएसएसटींग के साथ एक ही समस्या दिखाई देती है। यह तब भी प्रकट होता है जब मैं 64 बिट कर्नेल बूट करता हूं। (स्टार्टअप पर 64 होल्डिंग।)

ओएस 10.6.0

+0

क्या आपने स्मृति को देखने के लिए कई एनएसडीटा उदाहरणों को आवंटित करने और हटाने की कोशिश की है या नहीं उनमें से किसी के लिए पुनः दावा किया गया है? ऐसा हो सकता है कि प्रोग्राम स्मृति की कमी होने तक स्मृति को ओएस पर वापस नहीं लौटाता है। – Amok

+0

मैंने बस भाग्य के बिना 10.6 पर इसे पुन: उत्पन्न करने की कोशिश की। क्या आपने अपने परीक्षण ऐप के साथ एक बग दायर की है? – Ken

+0

आपका ऐप सही तरीके से व्यवहार कर रहा है और स्मृति को लीक नहीं कर रहा है। अर्ध-विस्तृत स्पष्टीकरण के लिए नीचे मेरा उत्तर देखें। – bbum

उत्तर

10

सबसे पहले, उपकरण के ऑब्जेक्ट ग्राफ़ उपकरण का उपयोग यह सत्यापित करने के लिए करें कि स्मृति अब उपयोग में नहीं माना जाता है; एक धारणा गिनती या कहीं मजबूत संदर्भ नहीं है।

यदि यह अब उपयोग में नहीं है, तो स्मृति बस चारों ओर चिपक रही है क्योंकि आपने उस सीमा को नहीं मारा है जिस पर संग्राहक परवाह है।

हालांकि, इस बयान:

64 बिट x86_64 कोई जीसी: कम से कम स्मृति मुक्त कर दिया है। जैसे 10%

मुझे सावधान करता है। विशेष रूप से, यदि आपका कोड गैर-जीसी में काम करने के लिए डिज़ाइन किया गया है - बनाए रखने/रिलीज़ के साथ - फिर या तो (ए) आपके पास मेमोरी लीक है और यदि सीएफआरटीन या किसी प्रकार का ग्लोबल कैश का उपयोग करना है, तो यह जीसी या (बी) आप यह पता लगाने के लिए सही टूल का उपयोग नहीं कर रहे हैं कि आपके पास मेमोरी रिसाव है या नहीं।

तो, आप कैसे निर्धारित कर रहे हैं कि आप स्मृति लीक कर रहे हैं?

अद्यतन; आप प्रक्रिया के आरएसआईजेई/वीएसआईजेई की निगरानी के लिए गतिविधि मॉनीटर का उपयोग कर रहे हैं। यह वास्तव में आपको "समय के साथ बढ़ने की प्रक्रिया" से परे कुछ भी उपयोगी नहीं बताएगा।

से नहीं (मैं स्रोत को देखा नहीं किया है) और अधिक संभावना है, यह कोड:

NSData *bla = [[NSData alloc] initWithContentsOfFile:@"/bigpoop"]; 

20MB फ़ाइल का कारण बन जाएगा mmap() 'होने की प्रक्रिया करने के लिए d। इसमें कोई मॉलोक() शैली आवंटन शामिल नहीं है। इसके बजाए, ओएस आपकी प्रक्रिया में 20 एमबी संगत पता स्थान रखता है और इसमें फ़ाइल की सामग्री को मानचित्र करता है। जैसे ही आप एनएसडीटा की सामग्री पढ़ते हैं, वैसे ही फ़ाइल में पेज गलती होगी जैसे आप जाते हैं।

जब आप bla जारी करते हैं, तो मैपिंग नष्ट हो जाती है। लेकिन इसका मतलब यह नहीं है कि वीएम उपप्रणाली आपके आवेदन की पता स्थान को 20 एमबी तक कम करने जा रही है।

तो, आप पता स्थान का एक समूह जला रहे हैं, लेकिन वास्तविक स्मृति नहीं। चूंकि आपकी प्रक्रिया 64 बिट्स है, इसलिए पता स्थान बहुत अधिक अनंत संसाधन है और पते का उपयोग करने के लिए बहुत कम लागत है, इस कारण ओएस को इस तरह लागू किया गया है।

आईई। कोई रिसाव नहीं है और आपका ऐप सही तरीके से व्यवहार कर रहा है, जीसी या नहीं।

यह एक आम गलतफहमी है और इस प्रकार, इस सवाल को तारांकित किया गया।

+0

मैं मेमोरी लीक उपकरणों का उपयोग कर रहा हूं। और 32 बिट बिल्ड के रूप में सबकुछ अपेक्षित काम करता है। – jsz

+0

कृपया मूल प्रश्न के लिए मेरे अपडेट पढ़ें। – jsz

+0

उत्तर के लिए धन्यवाद। ऐसा लगता है कि आप सही हैं :) – jsz

2

एक कचरा कलेक्टर जरूरी नहीं कि तुरंत स्मृति जारी करता है।

ऑब्जेक्टिव-सी कचरा कलेक्टर के मामले में, आप कोको का कचरा कलेक्टर एक collectIfNeeded संदेश आपत्ति जो बताते हैं कि अब collectExhaustively यह ऑर्डर करने के लिए तुरंत इकट्ठा करने शुरू करने के लिए कुछ संग्रह करने के लिए, या एक अच्छा समय हो सकता भेज सकते हैं किसी भी और सभी कचरा (लेकिन यह भी interruptible है)। the docs देखें।

0

मुझे आईफोनओएस 3.2 में एक बहुत ही समान समस्या है और मुझे सच में नहीं लगता कि स्मृति पुनः प्राप्त की जा रही है - मैं अंततः स्मृति चेतावनियों को ट्रिगर करता हूं। एक छोटा सा मौका है कि मैंने अपनी गलती को अनदेखा कर दिया है लेकिन मैं बहुत गहन रहा हूं।

मैं NSKeyedUnarchiver के अनारक्षित ओब्जेक्ट विथफाइल का उपयोग करता हूं: एक कस्टम ऑब्जेक्ट लोड करने के लिए जिसमें एक बड़ा एनएसडीटा और एक और बहुत छोटी वस्तु होती है। मेरी कस्टम ऑब्जेक्ट में डेलोक विधि को कॉल किया जाता है, एनएसडीटा ऑब्जेक्ट जारी किया जाता है, इसके पहले से retainCount == 1 पहले। भौतिक स्मृति किसी भी राशि से कम नहीं होती है, अकेले एनएसडीटा आकार का एक अंश दें, और पुनरावृत्ति स्मृति चेतावनियों के साथ विश्वसनीय रूप से उत्पन्न होते हैं: मेरे पास परीक्षण है जब तक कि मुझे वास्तव में स्तर 2 चेतावनियां प्राप्त नहीं होतीं।= (

रिलीज से पहले:

(gdb) पी (int) [(NSData *) pastItsWelcomeData retainCount]
$ 1 = 1

रिहाई के बाद:

(gdb) पी (पूर्णांक) [(NSData *) pastItsWelcomeData retainCount]
लक्ष्य इस संदेश चयनकर्ता का जवाब नहीं देता है।

+0

आपके पास एक अलग समस्या है। जीसी आईफोन पर मौजूद नहीं है, और 'retainCount' किसी भी तरह ऑब्जेक्ट-आजीवन समस्याओं को डीबग करने के लिए उपयोग करने वाली गलत बात है। (इसके बजाय इंस्ट्रूमेंट्स का उपयोग करें।) चूंकि यह एक अलग समस्या का वर्णन है और यह सवाल का जवाब नहीं देता है, आपको इसे एक अलग प्रश्न के रूप में पोस्ट करना चाहिए। –

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