2011-09-06 3 views
8

बनाता है मेरे पास एक ऐसा फ़ंक्शन है जो पैरामीटर के रूप में एक और कार्य करता है। कुछ इस तरह:एएस 3 पैरामीटर के रूप में फ़ंक्शन को पास करने से स्मृति लीक

public function onHits(target : Shape, callback : Function) : void 

मैं एक पैरामीटर है कि जब भी पारित कर दिया लक्ष्य कुछ हिट बुलाया जाना चाहिए के रूप में एक सदस्य समारोह पारित करके इसका इस्तेमाल। फ़ंक्शन को कई बार फ्रेम कहा जाता है। तो यह क्या कर रही द्वारा किया जाता है:

//code... 
CollisionManager.onHits(myShape, onHitCB); 
//code... 

हिट समारोह पर:

public function onHitCB(hitObject : *) : void 
{ 
    //removed all code to test this problem 
} 

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

तो यह स्पष्ट रूप से है जब मैं एचआईटीसीबी को उस पैरामीटर के रूप में पास करता हूं जो समस्या है। तो मैंने सोचा कि ऐसा इसलिए हो सकता है क्योंकि फ़्लैश फ़ंक्शन पॉइंटर बनाने के लिए कुछ मेमोरी आवंटित करता है और इसे रिलीज़ नहीं करता है लेकिन मैं सिस्टम.gc() को प्रत्येक फ्रेम को डीबग मोड में कॉल करता हूं और रिसाव अभी भी वहां है। इसका मतलब यह होगा कि यह एसडीके में एक बग है या मैं कुछ सही नहीं कर रहा हूं।

मैं एक चर कि समारोह जो मैं अपने वस्तु के निर्माता में आवंटित करने के लिए अंक रख कर एक अजीब वैकल्पिक हल मिल गया है:

private var func : Function; 

public function MyObject() 
{ 
    func = onHitCB; 
} 

और इस स्मृति रिसाव भले ही मैं अभी भी पारित साफ हो जाएगा onHitCB पैरामीटर के रूप में। तो इसका मतलब यह होगा कि यह एचआईटीसीबी प्राप्त करने के लिए "गेटर" फ़ंक्शन नहीं है लेकिन कुछ और मेमोरी रिसाव का कारण बनता है?

मैं बहुत उलझन में हूं। यह मेमोरी रिसाव का कारण कैसे बन सकता है:

public function MyObject() 
{ 
} 

public function update() : void 
{ 
    CollisionManager.onHits(myShape, onHitCB);//empty function 
} 

public function onHitCB(hitObject : *) : void 
{ 
    //removed all code to test this problem 
} 

लेकिन यह नहीं? :

private var func : Function; 
public function MyObject() 
{ 
    func = onHitCB; 
} 

public function update() : void 
{ 
    CollisionManager.onHits(myShape, onHitCB);//empty function 
} 

public function onHitCB(hitObject : *) : void 
{ 
    //removed all code to test this problem 
} 

और क्या इस कामकाज को करने की कोई आवश्यकता नहीं है?

+0

क्यों HitCB को CollisionManager के लिए क्लास सदस्य नहीं बनाते? आपके काम की तरह लगता है गुंजाइश खो रहा है। ऑन हिट्स की आखिरी पंक्ति पर कॉलबैक = शून्य की कोशिश करें; –

+0

ऑनबिट के अंत में कॉलबैक को शून्य पर सेट करने का प्रयास किया लेकिन रिसाव अभी भी मौजूद है। अब तक, फ़ंक्शन के लिए स्थानीय संदर्भ रखना एकमात्र कामकाज है जिसे मैं ढूंढने में सक्षम था। – Godfather

उत्तर

5

[...] जब आप एक पैरामीटर के रूप में एक विधि पारित बाध्य तरीकों स्वचालित रूप से बनाया जाता है। बाध्य विधियां यह सुनिश्चित करती हैं कि यह कीवर्ड हमेशा ऑब्जेक्ट या क्लास का संदर्भ देता है जिसमें एक विधि परिभाषित की जाती है। Source

ऐसा लगता है कि किसी विधि का संदर्भ बनाने की तरह एक साधारण गेटर का उपयोग नहीं किया जा रहा है। एक नई विधि बंद वस्तु उत्पन्न है। तो आपकी धारणा सही है।

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

+0

मैं देखता हूं, यह फ़ंक्शन पारित होने पर हर ऑब्जेक्ट के निर्माण के बारे में मेरे संदेह की पुष्टि करता है। हालांकि मुझे अभी भी समझ में नहीं आ रहा है कि फ़ंक्शन को पार करते हुए स्थानीय संदर्भ क्यों रखना (और स्थानीय संदर्भ नहीं) अब स्मृति रिसाव नहीं बनाएगा। – Godfather

+0

मुझे लगता है कि यह केवल तब उत्पन्न होता है जब * विधि नाम * सीधे उपयोग किया जाता है (असाइनमेंट पर या पैरामीटर के रूप में उपयोग किए जाने पर)। तो 'func = onHitCB;' विधि को बंद करने के लिए केवल एक बार विधि बंद कर देगा, क्योंकि पैरामीटर के रूप में पैरामीटर को फिर से उत्पन्न नहीं किया जाएगा। – Kapep

+0

हां, लेकिन मैं पैरामीटर के रूप में func का उपयोग नहीं कर रहा हूं, मैं अभी भी एचआईटीसीबी पर उपयोग कर रहा हूं (यदि आप ऊपर दिए गए 2 उदाहरणों पर ध्यान से देखते हैं, तो वे दोनों एचआईटीसीबी पर उपयोग करके हिट्स पर कॉल करते हैं) जो कि मेरे लिए सबसे बड़ी रहस्य है। मेरी सबसे अच्छी व्याख्या अभी यह होगी कि विधि बंद करने के लिए एक कमजोर संदर्भ के रूप में कैश किया जाता है जो आमतौर पर कचरा कलेक्टर द्वारा साफ किया जाता है लेकिन अज्ञात कारण के लिए नहीं होता है। चूंकि यह एक कमजोर संदर्भ है, इसलिए इसे प्रत्येक कॉल पर पुनर्जीवित करने की आवश्यकता होगी, लेकिन जब से मैं स्थानीय रूप से संदर्भ रखता हूं, तब तक यह बाद में कॉल पर पुन: उपयोग करने के लिए काफी समय तक जीवित रहता है। – Godfather

0

मुझे यकीन नहीं है कि आपका कोड ऑनट फ़ंक्शन में क्या है, लेकिन यदि किसी अन्य चक्र में इसे समाप्त करने के लिए अतिरिक्त समय की आवश्यकता नहीं है। तो मैं सिफारिश आप इस तरह करना है:

static public function onHits(target : Shape) : * 
{ 
    // do what you need 

    // return the hitObject; 
    return hitObject; 
} 

और

public function update() : void 
{ 
    // parse the object direc to to the function. 
    onHitCB (CollisionManager.onHits(myShape)); 
} 

public function onHitCB(hitObject : *) : void 
{ 
    if (hitObject == null) 
     return; 

    // if it not null then do all your calculations. 
    //removed all code to test this problem 
} 
+0

फिलहाल, ऑनहिट फ़ंक्शन कुछ भी नहीं करता है। मैंने इसे से सभी कोड हटा दिए हैं, फिर भी इसे फ़ंक्शन पॉइंटर पास करके इसे कॉल करना एक स्मृति रिसाव बनाएगा। मैं अपने कोड के डिज़ाइन को बदलकर समस्या से बच सकता हूं लेकिन फ़ंक्शन पॉइंटर को पास करने से इस समस्या का कारण नहीं बनना चाहिए (>। <) – Godfather

1

जब आप कार्यात्मक तकनीकों का उपयोग करते हैं तो मेमोरी लीक का कारण क्या होता है और इसके कारण अधिक जानकारी के लिए, http://www.developria.com/2010/12/functional-actionscript-part-1.html देखें। साथ ही, ध्यान रखें कि इस तरह की स्थिर विधियों का उपयोग करना वास्तव में खराब अभ्यास है (http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/), और आप बस शुरुआत कर रहे हैं इस तकनीक का उपयोग कर कई समस्याओं का सामना करना पड़ता है। ऐसा लगता है कि आप अपने प्रोजेक्ट में काफी जल्दी हैं कि आप इस पथ के लिए पूरी तरह प्रतिबद्ध नहीं हैं, इसलिए आप इसे प्रोग्राम करने के अन्य तरीकों को देखना चाहेंगे।

-1

और यही कारण है कि हम ओओपी शैली प्रोग्रामिंग में इस तरह की चीज नहीं करते हैं।
आपकी सबसे अच्छी शर्त यह ठीक से करना है और CollisionManager क्लास में कॉलबैक जोड़ें।
जब आप स्थानीय संदर्भ रखते हैं तो जीसीड किया जा सकता है क्योंकि फ़ंक्शन कभी भी गुंजाइश खो देता है क्योंकि उस var में संदर्भ होता है।
एक बार कुछ गुंजाइश खो देता है तो यह जीसी के लिए लगभग असंभव हो जाता है।

इसे आज़माएं और देखें कि आप किस प्रकार खोपड़ी खो देते हैं।

private var somevar:String = 'somevar with a string'; 
public function MyObject() 
{ 
} 

public function update() : void 
{ 
    CollisionManager.onHits(myShape, onHitCB);//empty function 
} 

public function onHitCB(hitObject : *) : void 
{ 
    trace(this.somevar) // scope should be lost at this point and somevar should be null or toss an error. 
} 
+0

क्या यह काम नहीं करना चाहिए? मुझे यकीन नहीं है कि गुंजाइश खोने का मतलब क्या है (फ़ंक्शन पॉइंटर्स उदाहरण के संदर्भ में रहते हैं कि वे सदस्य हैं इसलिए उन्हें इस तर्क के दाहिनी ओर बुलाया जा सकता है)। पैरामीटर द्वारा एक फ़ंक्शन पास करना ठीक काम करता है और "स्ट्रिंग के साथ कुछवर" जैसा दिखता है (मुझे लगता है?)। मुझे नहीं लगता कि एक कॉलबैक फ़ंक्शन क्यों पारित किया जाना चाहिए जिसे टकराव का पता लगाया जाना चाहिए "खराब डिज़ाइन" हो सकता है, प्रत्येक ऑब्जेक्ट संभवतः टकराव को अलग-अलग संभाल सकता है। इसका उपयोग कई मामलों में किया जाता है (बॉक्स 2 डी यह मेरे टकराव इंजन के लिए करता है) क्योंकि यह अधिक लचीला है। – Godfather

+0

ठीक है बुरा उदाहरण। अगर मुझे समय मिलता है तो मैं आपके लिए एक संपादन पोस्ट करूँगा जो बेहतर तरीके से समझाता है कि मैं किस बारे में बात कर रहा था। –

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