`स्टैकलोक` कीवर्ड का व्यावहारिक उपयोग


134

क्या किसी ने कभी stackallocC # में प्रोग्रामिंग करते हुए उपयोग किया है? मुझे पता है कि क्या होता है, लेकिन मेरे कोड में दिखाई देने वाली एकमात्र घटना दुर्घटना से होती है, क्योंकि Intellisense यह सुझाव देता है जब मैं टाइप करना शुरू करता हूं static, उदाहरण के लिए।

हालाँकि यह उपयोग परिदृश्यों से संबंधित नहीं है stackalloc, लेकिन मैं वास्तव में अपने ऐप्स में विरासत की एक बड़ी मात्रा में काम करता हूं, इसलिए हर बार और फिर मैं unsafeकोड का उपयोग करने का सहारा ले सकता हूं । लेकिन फिर भी मैं आमतौर पर unsafeपूरी तरह से बचने के तरीके खोजता हूं ।

और .Net में एक एकल थ्रेड के लिए स्टैक आकार के बाद से ~ 1 एमबी (सही होने पर मुझे सही करें), मैं उपयोग करने से और भी अधिक आरक्षित हूं stackalloc

क्या कुछ व्यावहारिक मामले हैं जहां कोई कह सकता है: "यह मेरे लिए असुरक्षित और उपयोग करने के लिए डेटा और प्रसंस्करण की सही मात्रा है stackalloc"?


5
सिर्फ इतना है कि देखा System.Numbersका उपयोग करता है यह एक बहुत referencesource.microsoft.com/#mscorlib/system/...
Slai

जवाबों:


150

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

प्रदर्शन के अनुसार, यदि आप उपयोग करते हैं stackallocतो डेटा की स्थानीयता के कारण सीपीयू पर कैश हिट की संभावना बहुत बढ़ जाती है।


26
डेटा की स्थानीयता, अच्छी बात! जब आप कई संरचनाओं या सरणियों को आवंटित करना चाहते हैं तो प्रबंधित मेमोरी शायद ही कभी प्राप्त होगी। धन्यवाद!
Groo

22
ढेर आवंटन आम तौर पर प्रबंधित वस्तुओं के लिए तेजी से होते हैं क्योंकि अप्रबंधित के लिए कोई मुफ्त सूची नहीं है; CLR हीप पॉइंटर को बढ़ाता है। स्थानीयता के लिए, अनुक्रमिक आवंटन लंबे समय से चल रही प्रबंधित प्रक्रियाओं के लिए ढेर के संघटन के कारण समाप्त होने की अधिक संभावना है।
शिया

1
"यह एक ढेर सरणी से आवंटित करने के लिए तेज़ है" ऐसा क्यों है? सिर्फ इलाका? किसी भी तरह से यह सिर्फ एक संकेतक-टक्कर है, नहीं?
मैक्स बाराक्लॉ

2
@MaxBarraclough क्योंकि आप जीसी लागत को आवेदन जीवन भर के लिए आवंटन को जोड़ते हैं। कुल आवंटन लागत = आबंटन + निपटारा, इस मामले में सूचक बम्प + जीसी हीप, बनाम सूचक बम्प + पॉइंटर डीक्रीमेंट स्टैक
पॉप कैटालिन

35

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


25

stackallocकेवल असुरक्षित कोड के लिए प्रासंगिक है। प्रबंधित कोड के लिए आप यह तय नहीं कर सकते कि डेटा कहाँ आवंटित किया जाए। स्टैक प्रति डिफ़ॉल्ट पर मान प्रकार आवंटित किए जाते हैं (जब तक कि वे एक संदर्भ प्रकार का हिस्सा नहीं होते हैं, जिस स्थिति में उन्हें ढेर पर आवंटित किया जाता है)। संदर्भ प्रकार ढेर पर आवंटित किए जाते हैं।

एक सादे वेनिला .NET अनुप्रयोग के लिए डिफ़ॉल्ट स्टैक का आकार 1 एमबी है, लेकिन आप इसे पीई हेडर में बदल सकते हैं। यदि आप स्पष्ट रूप से थ्रेड शुरू कर रहे हैं, तो आप कंस्ट्रक्टर अधिभार के माध्यम से एक अलग आकार भी निर्धारित कर सकते हैं। ASP.NET अनुप्रयोगों के लिए डिफ़ॉल्ट स्टैक आकार केवल 256K है, जो कि दो वातावरणों के बीच स्विच करने पर ध्यान में रखने के लिए कुछ है।


क्या दृश्य स्टूडियो से डिफ़ॉल्ट स्टैक आकार को बदलना संभव है?
विन्यासकर्ता

@configurator: जहां तक ​​मुझे जानकारी है, नहीं।
ब्रायन रासमुसेन

17

स्‍पैक्‍लोक का आरंभिक फैलाव। C # के पिछले संस्करणों में, स्टैकलॉक के परिणाम को केवल एक सूचक स्थानीय चर में संग्रहीत किया जा सकता है। C # 7.2 के रूप में, स्टैकलॉक का उपयोग अब एक अभिव्यक्ति के हिस्से के रूप में किया जा सकता है और एक स्पैन को लक्षित कर सकता है, और यह असुरक्षित कीवर्ड का उपयोग किए बिना किया जा सकता है। इस प्रकार, लिखने के बजाय

Span<byte> bytes;
unsafe
{
  byte* tmp = stackalloc byte[length];
  bytes = new Span<byte>(tmp, length);
}

आप बस लिख सकते हैं:

Span<byte> bytes = stackalloc byte[length];

यह उन स्थितियों में भी बेहद उपयोगी है, जहाँ आपको ऑपरेशन करने के लिए कुछ स्क्रैच स्पेस की आवश्यकता होती है, लेकिन अपेक्षाकृत छोटे आकारों के लिए ढेर मेमोरी आवंटित करने से बचना चाहते हैं

Span<byte> bytes = length <= 128 ? stackalloc byte[length] : new byte[length];
... // Code that operates on the Span<byte>

स्रोत: C # - सभी स्पैन के बारे में: एक नई .NET मेनस्टाइल की खोज


4
पारितोषिक के लिए धन्यवाद। ऐसा लगता है कि C # का प्रत्येक नया संस्करण C ++ के थोड़ा सा करीब आता है, जो वास्तव में एक अच्छी बात है IMHO।
ग्रू

1
जैसा कि यहां और यहां देखा जा सकता है , Spanयह .NET फ्रेमवर्क 4.7.2 में उपलब्ध नहीं है और यहां तक ​​कि 4.8 में भी नहीं है ... ताकि नई भाषा की सुविधा अभी भी सीमित उपयोग के लिए है।
फ्रेडरिक

2

इस सवाल में कुछ बेहतरीन जवाब हैं लेकिन मैं सिर्फ यह बताना चाहता हूं

Stackalloc का उपयोग मूल API को कॉल करने के लिए भी किया जा सकता है

कई मूल कार्यों को कॉलर को रिटर्न परिणाम प्राप्त करने के लिए एक बफर आवंटित करने की आवश्यकता होती है। उदाहरण के लिए, CfGetPlaceholderInfo फ़ंक्शन में cfapi.hनिम्न हस्ताक्षर हैं।

HRESULT CfGetPlaceholderInfo(
HANDLE                    FileHandle,
CF_PLACEHOLDER_INFO_CLASS InfoClass,
PVOID                     InfoBuffer,
DWORD                     InfoBufferLength,
PDWORD                    ReturnedLength);

इंटर # के माध्यम से इसे C # में कॉल करने के लिए,

[DllImport("Cfapi.dll")]
public static unsafe extern HResult CfGetPlaceholderInfo(IntPtr fileHandle, uint infoClass, void* infoBuffer, uint infoBufferLength, out uint returnedLength);

आप स्टैकलॉक का उपयोग कर सकते हैं।

byte* buffer = stackalloc byte[1024];
CfGetPlaceholderInfo(fileHandle, 0, buffer, 1024, out var returnedLength);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.