2009-12-11 11 views
22

मैं निम्नलिखित struct है:Marshal.AllocHGlobal वी.एस. Marshal.AllocCoTaskMem, Marshal.SizeOf वी.एस. sizeof()

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
public struct WAVEHDR 
{ 
    internal IntPtr lpData; // pointer to locked data buffer 
    internal uint dwBufferLength; // length of data buffer 
    internal uint dwBytesRecorded; // used for input only 
    internal IntPtr dwUser; // for client's use 
    internal uint dwFlags; // assorted flags (see defines) 
    internal uint dwLoops; // loop control counter 
    internal IntPtr lpNext; // reserved for driver 
    internal IntPtr reserved; // reserved for driver 
} 

मैं ऊपर struct का एक उदाहरण स्टोर करने के लिए अप्रबंधित स्मृति को आबंटित करने की जरूरत है। इस स्ट्रक्चर के लिए पॉइंटर को waveOut win32 एपीआई फ़ंक्शंस (waveOutPrepareHeader, waveOutWrite, waveOutUnprepareHeader) में पास किया जाएगा।

  1. क्या मुझे Marshal.AllocHGlobal() या Marshal.AllocCoTaskMem() का उपयोग करना चाहिए? अंतर क्या है?
  2. क्या मुझे मेमोरी आवंटन विधि में sizeof(WAVEHDR) या Marshal.SizeOf(typeof(WAVEHDR)) पास करना चाहिए? अंतर क्या है?

ध्यान दें कि आवंटित स्मृति को पिन किया जाना चाहिए।

उत्तर

38

एक विंडोज प्रोग्राम में कम से कम दो ढेर होते हैं जिसमें अप्रबंधित स्मृति आवंटित की जाती है। सबसे पहले डिफ़ॉल्ट प्रक्रिया ढेर है, जिसे विंडोज द्वारा उपयोग किया जाता है जब इसे प्रोग्राम की ओर से स्मृति आवंटित करने की आवश्यकता होती है। दूसरा आवंटित करने के लिए COM बुनियादी ढांचे द्वारा उपयोग किया जाने वाला एक ढेर है। .NET P/Invoc marshaller मानता है कि इस ढेर का उपयोग किसी भी अप्रबंधित कोड द्वारा किया गया था जिसका फ़ंक्शन हस्ताक्षर स्मृति आवंटित करने की आवश्यकता है।

AllocHGlobal प्रक्रिया ढेर से आवंटित, AllocCoTaskMem COM ढेर से आवंटित करता है।

जब भी आप अप्रबंधित इंटरऑप कोड लिखते हैं, तो आपको हमेशा ऐसी स्थिति से बचना चाहिए जहां अप्रबंधित स्मृति आवंटित कोड उस कोड के समान नहीं है जो इसे मुक्त करता है। एक अच्छा मौका होगा कि गलत डी-आवंटक का उपयोग किया जाता है। यह किसी भी कोड के लिए विशेष रूप से सच है जो सी/सी ++ प्रोग्राम के साथ इंटरपोज़ करता है। इस तरह के कार्यक्रमों में अपना स्वयं का आवंटक होता है जो स्टार्टअप पर सीआरटी द्वारा बनाई गई अपने ही ढेर का उपयोग करता है। अन्य कोड में ऐसी स्मृति को आवंटित करना असंभव है, आप विश्वसनीय रूप से ढेर हैंडल प्राप्त नहीं कर सकते हैं। यह P/Invoke परेशानी का एक बहुत ही आम स्रोत है, विशेष रूप से क्योंकि XP ​​में HeapFree() फ़ंक्शन और पहले चुपचाप याद दिलाने के लिए अनुरोधों को अनदेखा करता है जो सही ढेर में आवंटित नहीं किया गया था (आवंटित स्मृति को लीक करना) लेकिन Vista और Win7 क्रैश एक अपवाद के साथ कार्यक्रम।

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

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

आपको किसी इंटरऑप परिदृश्य में आकार() का कभी भी उपयोग नहीं करना चाहिए। यह मूल्य प्रकार के प्रबंधित आकार देता है। P/Invoke marshaller ने [स्ट्रक्चरलाउट] और [मार्शल] निर्देशों के अनुसार संरचना प्रकार का अनुवाद करने के बाद ऐसा नहीं हो सकता है। केवल मार्शल.SizeOf() आपको एक गारंटीकृत सही मूल्य देता है।


अद्यतन: वीएस2012 में एक बड़ा बदलाव था। इसके साथ शामिल सी रनटाइम लाइब्रेरी अब अपने ही ढेर का उपयोग करने के बजाय डिफ़ॉल्ट प्रक्रिया ढेर से आवंटित करता है। दीर्घकालिक, जो AllocHGlobal को सफलता के लिए सबसे अधिक संभावित एवेन्यू बनाता है।

+1

क्या दो आवंटन कार्यों के बीच कोई प्रदर्शन अंतर है? – DxCK

+3

'AllocCoTaskMem' अधिक प्रदर्शनकारी है। 'AllocHGlobal'' लोकलऑलोक 'को कॉल करता है, जिसमें निम्न नोट है: "स्थानीय कार्यों में अधिक ओवरहेड होता है और अन्य मेमोरी प्रबंधन कार्यों की तुलना में कम सुविधाएं प्रदान करता है।" Https://msdn.microsoft.com/en-us/library/windows/desktop/aa366723(v=vs.85).aspx देखें – IamIC

2

1) मार्शल.एलोक एचजीलोबल निश्चित रूप से काम करेगा। मार्शल के लिए दस्तावेज़ों के आधार पर। AllocCoTaskMem, मार्शल। AllocCoTaskMem भी काम करना चाहिए।

2) मार्शल.SizeOf (टाइपऑफ (WAVEHDR) का उपयोग करें)। Although you can use the Marshal.SizeOf method, the value returned by this method is not always the same as the value returned by sizeof. Marshal.SizeOf returns the size after the type has been marshaled, whereas sizeof returns the size as it has been allocated by the common language runtime, including any padding.

1

2) मैं जानता हूँ कि जहाँ तक sizeof केवल प्रकार संकलन समय पर एक पूर्वनिर्धारित आकार है के साथ प्रयोग किया जा सकता है।

तो Marshal.SizeOf(typeof(WAVEHDR)) का उपयोग करें।