2012-05-30 6 views
16

मैं विंडोज प्रोग्रामिंग के लिए नया हूं और मैंने बस एक बग शिकार करने में दो घंटे "खो दिया" है, जिसे हर किसी के बारे में पता है: आप डीएलएल में ढेर पर ऑब्जेक्ट नहीं बना सकते हैं और इसे किसी अन्य डीएलएल में नष्ट कर सकते हैं (या मुख्य में कार्यक्रम)।क्या (स्थिर रूप से जुड़े) डीएलएल मुख्य कार्यक्रम की तुलना में एक अलग ढेर का उपयोग करते हैं?

मुझे यकीन है कि लिनक्स/यूनिक्स पर यह मामला नहीं है (यदि ऐसा है, तो कृपया इसे कहें, लेकिन मुझे पूरा यकीन है कि मैंने समस्याओं के बिना हजारों बार ऐसा किया है ...)।

1) स्थिर जुड़ा हुआ DLLs मुख्य कार्यक्रम से एक अलग ढेर का उपयोग करें:

इस बिंदु पर मैं सवालों की एक जोड़ी है?

2) क्या सांख्यिकीय रूप से जुड़े डीएलएल मुख्य कार्यक्रम की उसी प्रक्रिया स्थान में मैप किए गए हैं? (मुझे पूरा यकीन है कि यहां का जवाब एक बड़ा हां है अन्यथा यह मुख्य कार्यक्रम में किसी फ़ंक्शन से डीएलएल में फ़ंक्शन में गुजरने वाले पॉइंटर्स को समझ में नहीं आता है)।

मैं सादा/नियमित DLL, नहीं कॉम/ATL सेवाओं

संपादित करें के बारे में बात कर रहा हूँ: द्वारा "स्थैतिक रूप से जुड़ा हुआ" मेरा मतलब है कि मैं DLL लोड करने के लिए LoadLibrary का उपयोग नहीं करते लेकिन मैं ठूंठ पुस्तकालय के साथ लिंक

+3

यह प्रत्येक मॉड्यूल के लिए सेटिंग्स पर निर्भर करता है। आम तौर पर यदि दो मॉड्यूल गतिशील सीआरटी का उपयोग करते हैं तो वे ढेर साझा करते हैं क्योंकि दोनों के पास सीआरटी लोड होने का एक ही उदाहरण होता है। यदि कोई मॉड्यूल स्थैतिक सीआरटी का उपयोग करता है तो उसके पास स्वयं का ढेर होता है क्योंकि इसमें सीआरटी का अपना उदाहरण होता है जिसमें – Luke

+1

@Luke - इसके अतिरिक्त, डायनामिक (डीएलएल) सीआरटी के विभिन्न संस्करणों का उपयोग करने के लिए विभिन्न मॉड्यूल के लिए संभव है, और इसलिए अलग ढेर। – Bukes

+0

यदि आप इसके बारे में सोचते हैं, तो हर गैर-तुच्छ डीएलएल बहुत ही ढेर बना देगा। एक उदाहरण के रूप में ओपन पुस्तकालय ले लो। आप डेटा को बफर ऑब्जेक्ट में फ़ीड कर सकते हैं (lib डेटा की अपनी प्रति बना देता है), कुछ पैरामीटर सेट करें, और लाइब्रेरी ध्वनि बजाएगी - बढ़िया, आसान, सही, कोई चिंता नहीं। अब कल्पना करें कि _two_ प्रोग्राम लाइब्रेरी लोड करते हैं। डेटा कहां रखना है, इसका मालिक कौन है? भौतिक RAM के किस हिस्से में यह है? क्या मैं चाहता हूं कि "कुछ अन्य प्रोग्राम" मेरे प्रोग्राम के ढेर पर डेटा देखने (या संशोधित) करने में सक्षम हो? यदि यह आपके मुख्य मॉड्यूल के ढेर पर रहता है, तो आप परेशानी में हैं ... – Damon

उत्तर

16

डीएलएल/पूर्व को सी रन टाइम लाइब्रेरी के कार्यान्वयन से लिंक करने की आवश्यकता होगी।

सी विंडोज रनटाइम पुस्तकालयों के मामले में, आप, बताने का विकल्प है यदि आप निम्न से लिंक करना चाहते हैं:

  1. एकल पिरोया सी रन समय पुस्तकालय (एकल थ्रेड पुस्तकालयों के लिए समर्थन बंद कर दिया गया अब)
  2. मल्टी-थ्रेडेड डीएलएल/मल्टी-थ्रेडेड डीबग डीएलएल
  3. स्टेटिक रन टाइम लाइब्रेरीज़।
  4. कुछ अधिक (लिंक आप देख सकते हैं)

उनमें से हर एक, एक अलग ढेर की चर्चा करते हुए किया जाएगा ताकि आप की अनुमति नहीं है पास पता दूसरे के क्रम पुस्तकालय के ढेर से प्राप्त।

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

सावधानीरन-टाइम पुस्तकालयों के स्थिर और गतिशील संस्करणों मिश्रण मत करो:

कृपया सी रन टाइम पुस्तकालयों के बारे में अधिक जानकारी प्राप्त कर here & here

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

+0

मैं किसी भी प्रकार के डीएलएल के बारे में बात कर रहा हूं, जरूरी नहीं कि सी रनटाइम कोड – Emiliano

+1

युक्त आरटीएल के प्रत्येक संस्करण को विभिन्न ढेर का उपयोग क्यों करना चाहिए? – osgx

+0

अब मैं समस्या को समझता हूं। लेकिन मॉड्यूल सीमाओं में एक सूचक पास करना सुरक्षित होना चाहिए, है ना? (जब तक ऑब्जेक्ट को इस दौरान नष्ट नहीं किया गया है, निश्चित रूप से और जब तक मुख्य कार्यक्रम और डीएलएल दोनों एक ही कंपाइलर के साथ संकलित किए जाते हैं) – Emiliano

3

यदि मेरे पास एक ऐसा एप्लिकेशन है जो .exe के रूप में संकलित करता है और मैं लाइब्रेरी का उपयोग करना चाहता हूं तो मैं या तो स्थिर रूप से लिंक कर सकता हूं एक .lib फ़ाइल से लाइब्रेरी या गतिशील रूप से उस .dll फ़ाइल से लाइब्रेरी को लिंक किया गया है।

प्रत्येक लिंक किए गए मॉड्यूल (यानी प्रत्येक .exe या .dll) को सी या सी ++ रन टाइम के कार्यान्वयन से जोड़ा जाएगा। रन टाइम स्वयं एक लाइब्रेरी होती है जो स्थिर या गतिशील रूप से जुड़ी हो सकती है और विभिन्न थ्रेडिंग कॉन्फ़िगरेशन में आ सकती है।

स्थिर रूप से जुड़े डीएलएस कहकर आप एक सेट अप का वर्णन कर रहे हैं जहां एक एप्लिकेशन .exe गतिशील रूप से लाइब्रेरी से लिंक करता है। डीएल और वह लाइब्रेरी आंतरिक रूप से रनटाइम से स्थिर रूप से लिंक होती है? मैं मानूंगा कि यह तुम्हारा मतलब है।

यह भी ध्यान देने योग्य है कि प्रत्येक मॉड्यूल (.exe या .dll) के पास स्टेटिक्स के लिए अपना दायरा है यानी .exe में वैश्विक स्थैतिक एक समान नाम के साथ एक वैश्विक स्टेटिक के समान नहीं होगा। ।

सामान्य मामले में इसलिए यह नहीं माना जा सकता है कि विभिन्न मॉड्यूल के अंदर चल रहे कोड रनटाइम के समान कार्यान्वयन का उपयोग कर रहे हैं, इसके अलावा वे किसी भी स्थिर स्थिति के समान उदाहरण का उपयोग नहीं करेंगे।

इसलिए मॉड्यूल सीमाओं को पार करने वाली वस्तुओं या पॉइंटर्स से निपटने के दौरान कुछ नियमों का पालन करने की आवश्यकता है। आवंटन और विध्वंस किसी भी दिए गए पते के लिए एक ही मॉड्यूल में होना चाहिए। अन्यथा ढेर मेल नहीं खाएंगे और व्यवहार को परिभाषित नहीं किया जाएगा।

COM संदर्भ गणना का उपयोग करके इसे हल करता है, संदर्भ संख्या शून्य तक पहुंचने पर स्वयं को हटा देती है। मिलान किए गए स्थान की समस्या को हल करने के लिए यह एक आम पैटर्न है।

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

2

आइए पहले विंडोज़ ओएस पर हमारे आवेदन/डीएलएल wrt को ढेर आवंटन और ढेर को समझें। पारंपरिक रूप से, ऑपरेटिंग सिस्टम और रन-टाइम पुस्तकालय ढेर के कार्यान्वयन के साथ आते हैं।

  1. प्रक्रिया की शुरुआत में, ओएस प्रोसेस हेप नामक एक डिफ़ॉल्ट ढेर बनाता है। प्रक्रिया ढेर का उपयोग ब्लॉक को आवंटित करने के लिए किया जाता है यदि कोई अन्य ढेर उपयोग नहीं किया जाता है।
  2. भाषा रन समय भी एक प्रक्रिया के भीतर अलग ढेर बना सकते हैं। (उदाहरण के लिए, सी रन टाइम अपने आप का एक ढेर बनाता है।)
  3. इन समर्पित ढेर के अलावा, एप्लिकेशन प्रोग्राम या कई लोड किए गए डायनामिक-लिंक लाइब्रेरीज़ (डीएलएल) में से एक अलग ढेर बना सकता है और निजी ढेर कहा जाता है, जिसे
  4. कहा जाता है
  5. ये ढेर सभी वर्चुअल मेमोरी सिस्टम में ऑपरेटिंग सिस्टम के वर्चुअल मेमोरी मैनेजर के शीर्ष पर बैठते हैं।
    1. C/C++ रन-समय (सीआरटी) संभाजक:
    2. के CRT और संबद्ध ढेर के बारे में अधिक चर्चा करते हैं malloc() और() के साथ-साथ नए प्रदान करता है और ऑपरेटरों को हटा दें।
    3. सीआरटी अपने सभी आवंटन के लिए एक अतिरिक्त ढेर बनाता है (इस सीआरटी ढेर के हैंडल को सीआरटी लाइब्रेरी में आंतरिक रूप से _crtheap नामक वैश्विक चर में संग्रहीत किया जाता है) इसके प्रारंभिक भाग के हिस्से के रूप में।
    4. सीआरटी अपने स्वयं के निजी ढेर बनाता है, जो विंडोज ढेर के शीर्ष पर रहता है।
    5. विंडोज हीप विंडोज रन-टाइम आवंटक (एनटीडीएलएल) के आस-पास एक पतली परत है।
    6. विंडोज रन-टाइम आवंटक वर्चुअल मेमोरी ऑलोकेटर के साथ इंटरैक्ट करता है, जो ओएस द्वारा उपयोग किए जाने वाले पृष्ठों को आरक्षित करता है और करता है।

आपका DLL और बहु-क्रम स्थिर सीआरटी पुस्तकालयों के लिए exe लिंक। आपके द्वारा बनाए गए प्रत्येक डीएलएल और एक्सई का अपना ही ढेर होता है, यानी _crtheap। आवंटन और डी-आवंटन संबंधित ढेर से होना होता है। डीएलएल से गतिशील रूप से आवंटित, निष्पादन योग्य और इसके विपरीत से आवंटित नहीं किया जा सकता है।

आप क्या कर सकते हैं? रन-टाइम लाइब्रेरी के मल्टीथ्रेड-विशिष्ट और डीएलएल-विशिष्ट संस्करण का उपयोग करने के लिए डीएलएल और एक्सई का उपयोग/एमडी या/एमडीडी में हमारे कोड को संकलित करें। इसलिए डीएलएल और एक्सई दोनों एक ही सी रन टाइम लाइब्रेरी से जुड़े हुए हैं और इसलिए एक _crtheap। आवंटन हमेशा एक मॉड्यूल के भीतर डी-आवंटन के साथ जोड़ा जाता है।

+0

लिनक्स पर हालांकि, मुझे यकीन नहीं है कि जब आप अपने डीएलएल (साझा लाइब्रेरी) और एक्सई के साथ स्टेटिक सी रन टाइम लाइब्रेरी को लिंक करते हैं तो क्या होता है? क्या हम भी एक ही समस्या का सामना करेंगे? –

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