2009-10-28 12 views
8

में आवंटित स्मृति को खाली करना मेरे पास एक डीएलएल फ़ाइल का उपयोग कर एक EXE फ़ाइल है जो एक और DLL फ़ाइल का उपयोग कर रही है। यह स्थिति उत्पन्न हो गई है:एक अलग DLL

DLL फ़ाइल 1:

class abc 
{ 
    static bool FindSubFolders(const std::string & sFolderToCheck, 
           std::vector<std::string> & vecSubFoldersFound); 
} 

DLL फ़ाइल 2 में:

void aFunction() 
{ 
    std::vector<std::string> folders; 
    std::string sLocation; 
    ... 
    abc::FindSubFolders(sLocation, folders) 
} 

रिलीज़ मोड में, सब कुछ ठीक काम करता है। लेकिन डिबग मोड में, मैं फ़ोल्डरों वेक्टर में std::strings में से एक की नाशक में एक अभिकथन विफलता के साथ आते हैं (जब फ़ोल्डरों aFunction के अंत में क्षेत्र से बाहर चला जाता है):

dbgheap.c : line 1274

/* 
* If this ASSERT fails, a bad pointer has been passed in. It may be 
* totally bogus, or it may have been allocated from another heap. 
* The pointer MUST come from the 'local' heap. 
*/ 
_ASSERTE(_CrtIsValidHeapPointer(pUserData)); 

मुझे लगता है कि यह इसलिए है क्योंकि स्मृति को डीएलएल फ़ाइल 1 के ढेर पर आवंटित किया गया है, लेकिन डीएलएल फाइल 2 में मुक्त किया जा रहा है।

dbgheap.c में टिप्पणी बहुत जोर देती है कि यह एक समस्या है।

क्यों इस तरह के एक समस्या, जब यह करता है, तो मैं बस इसे अनदेखा ठीक से काम करने लगता है है? क्या ऐसा करने का एक गैर-दावा-असफल तरीका है?

+2

डॉट। नज़रअंदाज़ करना । आकलन – KeatsPeeks

+22

नहीं। अनदेखी। आईटी। ऐसा इसलिए है। क्यूं कर। मैंने पूछा। = पी – Smashery

+0

बस जानना चाहते हैं * क्यों * यह एक समस्या है। – Smashery

उत्तर

11

शॉन जैसा कि पहले ही कहा है, रिहाई का निर्माण बस पर ध्यान नहीं देता है कि नष्ट बयान है, तो सबसे अच्छा आप के लिए आशा कर सकते हैं एक स्मृति रिसाव है।

यदि आपके पास डीएलएल फाइलों को संकलित करने के तरीके पर नियंत्रण है, तो रनटाइम लाइब्रेरी के लिए मल्टी-थ्रेडेड डीबग डीएलएल (/ एमडीडी) या मल्टी-थ्रेडेड डीएलएल (/ एमडी) सेटिंग्स का उपयोग करना सुनिश्चित करें। इस तरह, दोनों डीएलएल फाइलें एक ही रनटाइम सिस्टम का उपयोग करेंगी और उसी ढेर को साझा करेंगी।

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

+0

मेरी परियोजना गुण गलत थे - मेरे पास डीबग डीएलएल (/ एमडीडी) सेट नहीं था - अब यह ठीक काम करता है। धन्यवाद! – Smashery

6

सबसे अधिक संभावना है कि रिलीज बिल्ड में एक ही समस्या है, लेकिन रिलीज बिल्ड्स जोर नहीं देते हैं। वे सिर्फ समस्या को अनदेखा करते हैं। आप कभी भी कोई समस्या नहीं देख सकते हैं। या आप डेटा भ्रष्टाचार देख सकते हैं। या आप एक दुर्घटना देख सकते हैं। हो सकता है कि केवल आपके उपयोगकर्ता ही उन बग का अनुभव करेंगे जिन्हें आप पुन: उत्पन्न करने में सक्षम नहीं हैं।

सीआरटी दावों को अनदेखा न करें।

तुम हमेशा उचित deallocator (एक है कि के साथ शुरू करने के लिए इस्तेमाल संभाजक मेल खाता है) का उपयोग करना चाहिए। यदि आप अपनी डीएलएल फाइलों में स्थिर सीआरटी पुस्तकालयों का उपयोग कर रहे हैं, तो डीएलएल फाइलें अलग-अलग ढेर का उपयोग कर रही हैं। आप पूरे ढेर में स्मृति को हटा नहीं सकते हैं। एक ही ढेर का उपयोग कर स्मृति के ब्लॉक को आवंटित और हटा दें।

आप अपने DLL फ़ाइलों में साझा CRT लाइब्रेरी का उपयोग कर रहे हैं, तो वे एक ही ढेर का उपयोग कर होना चाहिए और आप एक DLL फ़ाइल और दूसरे में पुनःआवंटन में आवंटित कर सकते हैं।

+2

सीएफ। रेमंड चेन: http://blogs.msdn.com/oldnewthing/archive/2006/09/15/755966.aspx –

+0

+1 - धन्यवाद! – Smashery

5

यह केवल एक समस्या है, तो DLL फ़ाइलों के आवेदन या एक (या अधिक) मानक पुस्तकालय के स्थिर संस्करण के खिलाफ जुड़ा हुआ है। यह एक दशक पहले मानक पुस्तकालय के साझा पुस्तकालय संस्करण को जारी करने के द्वारा एमएस द्वारा हल किया गया था। ऐसा इसलिए है क्योंकि मानक लाइब्रेरी का प्रत्येक संस्करण इसे अपने आंतरिक ढेर का निर्माण करेगा और इस प्रकार एकाधिक ढेर के साथ आपको स्मृति को सही ढेर में छोड़ देना होगा। मानक पुस्तकालय के साझा संस्करण का उपयोग करके वे सभी एक ही ढेर का उपयोग करते हैं।

यह आजकल मानक अभ्यास है और सभी डीएलएल फ़ाइलों को मानक पुस्तकालय के गतिशील संस्करण का उपयोग करने के लिए बनाया जाना चाहिए।

उपर्युक्त के लिए एकमात्र चेतावनी यह है कि यदि आप अपना खुद का ढेर बनाते हैं और इस ढेर से स्मृति आवंटित करते हैं। लेकिन यह दुर्लभ स्थितियों में केवल एक बहुत ही विशिष्ट प्रक्रिया है (और यदि आप इसका उपयोग करने के लिए पर्याप्त समझते हैं तो आप इस प्रश्न पूछने की स्थिति में नहीं होंगे)।

6

जैसा कि अन्य कहते हैं, समस्या को हल करके हल किया जा सकता है कि सीआरटी को दो मॉड्यूल के बीच साझा किया जाता है। लेकिन ऐसे सामान्य परिदृश्य हैं जहां इस अनुबंध को लागू करना मुश्किल है।

कारण यह है कि साझा सीआरटी के खिलाफ लिंक करना सुनिश्चित नहीं होगा यदि EXE और DLL उसी CRT संस्करण (6.0, 7.0, 8.0 में) के विरुद्ध लिंक नहीं करते हैं। उदाहरण के लिए यदि आप एक डीएलएल लेते हैं जिसे वीसी 6.0 में बनाया गया है और इसे VS2010 में EXE बिल्ड के साथ उपयोग करने का प्रयास करें तो आपको पहले जैसा ही समस्या मिल जाएगी। सीआरटी के दो संस्करण आपकी प्रक्रिया में लोड किए जाएंगे और प्रत्येक आवंटन के लिए अपने ही ढेर का उपयोग करेगा, भले ही आपका EXE और DLL 'साझा' सीआरटी का उपयोग करे, वे वही नहीं होंगे।

एपीआई के लिए एक बेहतर अभ्यास यह सुनिश्चित करना होगा कि एक तरफ आवंटित वस्तुओं को भी एक ही तरफ नष्ट कर दिया जाए। मुझे पता है कि यह बदसूरत लगता है लेकिन यह सुनिश्चित करने का एकमात्र तरीका है कि एक डीएलएल द्विआधारी संगत बना रहता है।