जब आप new
ऑपरेटर के साथ कक्षा का उदाहरण बनाते हैं, तो ढेर पर स्मृति आवंटित की जाती है। जब आप new
ऑपरेटर के साथ एक स्ट्रक्चर का उदाहरण बनाते हैं, तो ढेर या ढेर पर मेमोरी आवंटित की जाती है?क्या संरचना पर "नया" प्रयोग करना ढेर या ढेर पर आवंटित करता है?
उत्तर
ठीक है, देखते हैं कि मैं इसे किसी भी स्पष्ट कर सकता हूं या नहीं।
सबसे पहले, ऐश सही है: सवाल जहां मान प्रकार चर आवंटित किए जाते हैं के बारे में नहीं है। यह एक अलग सवाल है - और एक जिसका जवाब सिर्फ "ढेर पर" नहीं है। यह उससे अधिक जटिल है (और सी # 2 द्वारा और भी जटिल बना दिया गया है)। मेरे पास article on the topic है और अनुरोध किए जाने पर इसका विस्तार होगा, लेकिन चलिए new
ऑपरेटर से निपटें।
दूसरा, यह वास्तव में इस बात पर निर्भर करता है कि आप किस स्तर के बारे में बात कर रहे हैं।मैं देख रहा हूं कि आईएलएल के संदर्भ में, कंपाइलर स्रोत कोड के साथ क्या करता है। यह संभव है कि जेआईटी कंपाइलर काफी "लॉजिकल" आवंटन को अनुकूलित करने के मामले में चालाक चीजें करेगा।
तीसरा, मैं जेनेरिकों को अनदेखा कर रहा हूं, अधिकतर क्योंकि मुझे वास्तव में उत्तर नहीं पता है, और आंशिक रूप से क्योंकि यह चीजों को बहुत जटिल करेगा।
अंत में, यह सब केवल वर्तमान कार्यान्वयन के साथ है। सी # spec इस में से अधिक निर्दिष्ट नहीं करता है - यह प्रभावी ढंग से एक कार्यान्वयन विस्तार है। ऐसे लोग हैं जो मानते हैं कि प्रबंधित कोड डेवलपर्स को वास्तव में परवाह नहीं करना चाहिए। मुझे यकीन नहीं है कि मैं अब तक जाऊंगा, लेकिन यह एक ऐसी दुनिया की कल्पना करने लायक है जहां वास्तव में सभी स्थानीय चर ढेर पर रहते हैं - जो अभी भी कल्पना के अनुरूप होगा।
मूल्य प्रकार पर new
ऑपरेटर के साथ दो अलग-अलग स्थितियों हैं: आप एक parameterless निर्माता (जैसे new Guid()
) या एक parameterful निर्माता (जैसे new Guid(someString)
) कॉल कर सकते हैं या तो। ये काफी अलग आईएल उत्पन्न करते हैं। समझने के लिए, आपको सी # और सीएलआई चश्मा की तुलना करने की आवश्यकता क्यों है: सी # के अनुसार, सभी मान प्रकारों में पैरामीटर रहित कन्स्ट्रक्टर होता है। सीएलआई स्पेक के अनुसार, नहीं मूल्य प्रकारों में पैरामीटर रहित कन्स्ट्रक्टर हैं। (कुछ समय के प्रतिबिंब के साथ एक मूल्य प्रकार के रचनाकारों को प्राप्त करें - आपको पैरामीटर रहित नहीं मिलेगा।)
यह कन्स्ट्रक्टर के रूप में "शून्य के साथ मूल्य प्रारंभ करने" के इलाज के लिए सी # के लिए समझ में आता है, क्योंकि यह रखता है भाषा सुसंगत - आप new(...)
के रूप में हमेशा कन्स्ट्रक्टर को कॉल कर सकते हैं। सीएलआई के बारे में सोचने के लिए यह समझ में आता है, क्योंकि कॉल करने के लिए कोई वास्तविक कोड नहीं है - और निश्चित रूप से कोई टाइप-विशिष्ट कोड नहीं है।
यह भी एक फर्क पड़ता है कि आप इसे शुरू करने के बाद मूल्य के साथ क्या करने जा रहे हैं।
myInstanceOrStaticVariable = new Guid(someString);
इसके अलावा, मूल्य एक मध्यवर्ती मूल्य के रूप में प्रयोग किया जाता है, उदाहरण के लिए: आईएल
Guid localVariable = new Guid(someString);
आईएल के लिए अलग है के लिए इस्तेमाल किया के लिए इस्तेमाल किया एक विधि कॉल के लिए एक तर्क, चीजें फिर से थोड़ा अलग हैं। इन सभी मतभेदों को दिखाने के लिए, यहां एक छोटा परीक्षण कार्यक्रम है। यह स्थैतिक चर और आवृत्ति चर के बीच अंतर नहीं दिखाता है: आईएल stfld
और stsfld
के बीच भिन्न होगा, लेकिन यह सब कुछ है।
using System;
public class Test
{
static Guid field;
static void Main() {}
static void MethodTakingGuid(Guid guid) {}
static void ParameterisedCtorAssignToField()
{
field = new Guid("");
}
static void ParameterisedCtorAssignToLocal()
{
Guid local = new Guid("");
// Force the value to be used
local.ToString();
}
static void ParameterisedCtorCallMethod()
{
MethodTakingGuid(new Guid(""));
}
static void ParameterlessCtorAssignToField()
{
field = new Guid();
}
static void ParameterlessCtorAssignToLocal()
{
Guid local = new Guid();
// Force the value to be used
local.ToString();
}
static void ParameterlessCtorCallMethod()
{
MethodTakingGuid(new Guid());
}
}
यहाँ, वर्ग के लिए आईएल है (जैसे nops के रूप में) अप्रासंगिक बिट्स को छोड़कर:
.class public auto ansi beforefieldinit Test extends [mscorlib]System.Object
{
// Removed Test's constructor, Main, and MethodTakingGuid.
.method private hidebysig static void ParameterisedCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: stsfld valuetype [mscorlib]System.Guid Test::field
L_0010: ret
}
.method private hidebysig static void ParameterisedCtorAssignToLocal() cil managed
{
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: ldstr ""
L_0008: call instance void [mscorlib]System.Guid::.ctor(string)
// Removed ToString() call
L_001c: ret
}
.method private hidebysig static void ParameterisedCtorCallMethod() cil managed
{
.maxstack 8
L_0001: ldstr ""
L_0006: newobj instance void [mscorlib]System.Guid::.ctor(string)
L_000b: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0011: ret
}
.method private hidebysig static void ParameterlessCtorAssignToField() cil managed
{
.maxstack 8
L_0001: ldsflda valuetype [mscorlib]System.Guid Test::field
L_0006: initobj [mscorlib]System.Guid
L_000c: ret
}
.method private hidebysig static void ParameterlessCtorAssignToLocal() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
// Removed ToString() call
L_0017: ret
}
.method private hidebysig static void ParameterlessCtorCallMethod() cil managed
{
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Guid guid)
L_0001: ldloca.s guid
L_0003: initobj [mscorlib]System.Guid
L_0009: ldloc.0
L_000a: call void Test::MethodTakingGuid(valuetype [mscorlib]System.Guid)
L_0010: ret
}
.field private static valuetype [mscorlib]System.Guid field
}
जैसा कि आप देख सकते हैं, वहाँ निर्माता फोन करने के लिए इस्तेमाल किया विभिन्न निर्देश के बहुत सारे हैं:
newobj
: स्टैक पर मान आवंटित करता है, पैरामीटरयुक्त कन्स्ट्रक्टर को कॉल करता है। मध्यवर्ती मूल्यों के लिए प्रयुक्त, उदा। एक क्षेत्र के लिए असाइनमेंट या विधि तर्क के रूप में उपयोग के लिए।call instance
: पहले से आवंटित संग्रहण स्थान (चाहे ढेर पर या नहीं) का उपयोग करता है। स्थानीय चर को असाइन करने के लिए उपरोक्त कोड में इसका उपयोग किया जाता है। यदि एक ही स्थानीय चर को कईnew
कॉल का उपयोग करके कई बार मान दिया जाता है, तो यह पुराने मान के शीर्ष पर डेटा प्रारंभ करता है - यह हर बार अधिक स्टैक स्पेस आवंटित नहीं करता है।initobj
: पहले से आवंटित संग्रहण स्थान का उपयोग करता है और केवल डेटा मिटा देता है। यह हमारे सभी पैरामीटर रहित कन्स्ट्रक्टर कॉल के लिए उपयोग किया जाता है, जिसमें स्थानीय चर को असाइन किया जाता है। विधि कॉल के लिए, एक मध्यवर्ती स्थानीय चर प्रभावी ढंग से पेश किया जाता है, और इसका मूल्यinitobj
द्वारा मिटा दिया जाता है।
मुझे उम्मीद है कि यह दिखाता है कि विषय कितना जटिल है, जबकि एक ही समय में थोड़ा सा प्रकाश चमक रहा है। में वैचारिक इंद्रियां, new
पर प्रत्येक कॉल स्टैक पर स्थान आवंटित करता है - लेकिन जैसा कि हमने देखा है, यह वास्तव में आईएल स्तर पर भी नहीं होता है। मैं एक विशेष मामले को हाइलाइट करना चाहता हूं। इस विधि लें:
void HowManyStackAllocations()
{
Guid guid = new Guid();
// [...] Use guid
guid = new Guid(someBytes);
// [...] Use guid
guid = new Guid(someString);
// [...] Use guid
}
"तार्किक" 4 ढेर आवंटन किया गया है कि - ढेर केवल एक बार आवंटित किया जाता है लेकिन वास्तव में (कि विशिष्ट कोड के लिए) - चर के लिए, और तीन new
कॉल से प्रत्येक के लिए एक , और उसके बाद एक ही भंडारण स्थान का पुन: उपयोग किया जाता है।
संपादित करें: बस स्पष्ट होने के लिए, यह केवल कुछ मामलों में सच है ... विशेष रूप से guid
का मान दिखाई नहीं देगा यदि Guid
कन्स्ट्रक्टर अपवाद फेंकता है, यही कारण है कि सी # कंपाइलर सक्षम है एक ही ढेर स्लॉट का पुन: उपयोग करें। अधिक जानकारी के लिए एरिक लिपर्ट के blog post on value type construction देखें और एक मामला जहां लागू नहीं होता है।
मैंने इस उत्तर को लिखने में बहुत कुछ सीखा है - अगर इसमें से कोई अस्पष्ट नहीं है तो स्पष्टीकरण के लिए पूछें!
सभी मूल्य प्रकारों के साथ, structs हमेशा घोषित घोषित किए गए थे।
structs का उपयोग करने के बारे में अधिक जानकारी के लिए इस प्रश्न को here देखें। और इस प्रश्न here structs पर कुछ और जानकारी के लिए।
संपादित करें: मैं था mistankely जवाब है कि वे हमेशा ढेर में जाना। यह incorrect है।
"structs हमेशा जाना, जहां वे घोषित किया गया", यह थोड़ा भ्रमित भ्रामक है। कक्षा में एक संरचना क्षेत्र हमेशा "गतिशील स्मृति" में रखा जाता है जब प्रकार का एक उदाहरण बनाया जाता है "- जेफ रिक्टर। यह ढेर पर परोक्ष रूप से हो सकता है, लेकिन सामान्य संदर्भ प्रकार के समान नहीं है। – Ash
नहीं, मुझे लगता है कि यह * बिल्कुल * सही है - भले ही यह संदर्भ प्रकार के समान न हो। परिवर्तनीय जीवन का मूल्य जहां इसे घोषित किया जाता है। संदर्भ डेटा चर का मान वास्तविक डेटा की बजाय संदर्भ है, यह सब कुछ है। –
संक्षेप में, जब भी आप एक विधि में किसी भी प्रकार का मूल्य (घोषणा) बनाते हैं तो यह हमेशा ढेर पर बनाया जाता है। – Ash
स्ट्रक्क्स को ढेर में आवंटित किया जाता है। यहाँ एक उपयोगी विवरण है:
साथ ही, कक्षाओं जब नेट के भीतर instantiated स्मृति ढेर या .NET के आरक्षित स्मृति स्थान पर आवंटित। जबकि ढेर पर आवंटन के कारण तत्काल होने पर structs अधिक दक्षता उत्पन्न करते हैं। इसके अलावा, यह ध्यान दिया जाना चाहिए कि structs के भीतर पैरामीटर पास करना मूल्य के अनुसार किया जाता है।
यह उस स्थिति को कवर नहीं करता है जब एक वर्ग कक्षा का हिस्सा होता है - जिस बिंदु पर यह ऑब्जेक्ट के बाकी हिस्सों के साथ ढेर पर रहता है। –
हां लेकिन यह वास्तव में पूछे जाने वाले प्रश्न पर ध्यान केंद्रित करता है और जवाब देता है। वोट दिया – Ash
... जबकि अभी भी गलत और भ्रामक है। क्षमा करें, लेकिन इस सवाल का कोई संक्षिप्त जवाब नहीं है - जेफरी का एकमात्र पूरा जवाब है। –
संरचनाओं के खेतों वाली स्मृति को परिस्थितियों के आधार पर ढेर या ढेर पर आवंटित किया जा सकता है। यदि स्ट्रक्चर-टाइप वैरिएबल एक स्थानीय चर या पैरामीटर है जो किसी अज्ञात प्रतिनिधि या इटरेटर वर्ग द्वारा कैद नहीं किया जाता है, तो इसे स्टैक पर आवंटित किया जाएगा। यदि चर कुछ वर्ग का हिस्सा है, तो इसे ढेर पर कक्षा के भीतर आवंटित किया जाएगा।
यदि संरचना ढेर पर आवंटित की जाती है, तो नए ऑपरेटर को कॉल करना वास्तव में स्मृति आवंटित करने के लिए आवश्यक नहीं है। एकमात्र उद्देश्य क्षेत्र मूल्यों को कन्स्ट्रक्टर में जो भी हो, उसके अनुसार सेट करना होगा। यदि निर्माता को नहीं कहा जाता है, तो सभी फ़ील्ड को उनके डिफ़ॉल्ट मान (0 या शून्य) प्राप्त होंगे।
इसी प्रकार ढेर पर आवंटित structs के लिए, सिवाय इसके कि सी # को सभी स्थानीय चरों को उपयोग करने से पहले कुछ मूल्य पर सेट करने की आवश्यकता है, इसलिए आपको या तो कस्टम कन्स्ट्रक्टर या डिफ़ॉल्ट कन्स्ट्रक्टर (एक कन्स्ट्रक्टर जो कोई पैरामीटर नहीं लेता है हमेशा structs के लिए उपलब्ध है)।
बहुत सारे structs जिन्हें मान प्रकार माना जाता है, को ढेर पर आवंटित किया जाता है, जबकि वस्तुओं को ढेर पर आवंटित किया जाता है, जबकि वस्तु संदर्भ (सूचक) ढेर पर आवंटित किया जाता है।
इसे कॉम्पैक्टली रखने के लिए, नया structs के लिए एक गलत नामक है, जिसे नए कन्स्ट्रक्टर कहते हैं। संरचना के लिए एकमात्र भंडारण स्थान वह स्थान है जिसे परिभाषित किया गया है।
यदि यह एक सदस्य चर है तो इसे सीधे जो कुछ भी परिभाषित किया गया है, उसे सीधे संग्रहीत किया जाता है, यदि यह एक स्थानीय चर या पैरामीटर है जो इसे ढेर पर संग्रहीत किया जाता है।
कक्षाओं में इसकी तुलना करें, जहां संदर्भ पूरी तरह से संग्रहीत किया गया हो, जहां संदर्भ ढेर पर कहीं भी संदर्भित होता है। (भीतर सदस्य, स्थानीय/पैरामीटर पर पैरामीटर)
यह सी ++ में थोड़ा सा देखने में मदद कर सकता है, जहां कक्षा/संरचना के बीच वास्तविक भेद नहीं है। (भाषा में समान नाम हैं, लेकिन वे केवल चीजों की डिफ़ॉल्ट पहुंच को संदर्भित करते हैं) जब आप नए कॉल करते हैं तो आपको ढेर स्थान पर पॉइंटर मिलता है, जबकि यदि आपके पास गैर-पॉइंटर संदर्भ है तो यह सीधे स्टैक पर संग्रहीत होता है या अन्य वस्तु के भीतर, सी # में एला structs।
मुझे शायद यहां कुछ याद आ रहा है लेकिन हम आवंटन की परवाह क्यों करते हैं?
मूल्य प्रकार मूल्य से पारित होते हैं;) और इस प्रकार उन्हें परिभाषित किए जाने के मुकाबले एक अलग दायरे में उत्परिवर्तित नहीं किया जा सकता है। उस मान को म्यूट करने में सक्षम होने के लिए आपको [ref] कीवर्ड जोड़ना होगा।
संदर्भ प्रकार संदर्भ द्वारा पारित किए जाते हैं और उत्परिवर्तित किया जा सकता है।
निश्चित रूप से अपरिवर्तनीय संदर्भ प्रकार तार सबसे लोकप्रिय हैं।
सरणी लेआउट/प्रारंभ: मूल्य प्रकार -> शून्य स्मृति [नाम, ज़िप] [नाम, ज़िप] संदर्भ प्रकार -> शून्य स्मृति -> अशक्त [रेफरी] [रेफरी]
संदर्भ प्रकार संदर्भ द्वारा पारित नहीं किए जाते हैं - संदर्भ मूल्य से पारित होते हैं। यह बहुत अलग है। –
एक class
या struct
घोषणा एक ब्लूप्रिंट की तरह है जिसका उपयोग रन टाइम पर उदाहरण या ऑब्जेक्ट बनाने के लिए किया जाता है। यदि आप class
या struct
व्यक्ति को परिभाषित करते हैं, तो व्यक्ति इस प्रकार का नाम है। यदि आप एक प्रकार के प्रकार के व्यक्ति को घोषित और प्रारंभ करते हैं, तो पी को व्यक्ति का ऑब्जेक्ट या उदाहरण कहा जाता है। एक ही व्यक्ति प्रकार के कई उदाहरण बनाए जा सकते हैं, और प्रत्येक उदाहरण के properties
और fields
में अलग-अलग मान हो सकते हैं।
ए class
एक संदर्भ प्रकार है। जब class
का ऑब्जेक्ट बनाया गया है, तो वेरिएबल जिस पर ऑब्जेक्ट असाइन किया गया है केवल उस स्मृति का संदर्भ रखता है। जब ऑब्जेक्ट संदर्भ को एक नए चर के लिए आवंटित किया जाता है, तो नया चर मूल ऑब्जेक्ट को संदर्भित करता है। एक चर के माध्यम से किए गए परिवर्तन अन्य चर में दिखाई देते हैं क्योंकि वे दोनों एक ही डेटा को संदर्भित करते हैं।
ए struct
एक मूल्य प्रकार है। जब struct
बनाया गया है, तो वेरिएबल जिस पर struct
असाइन किया गया है, संरचना का वास्तविक डेटा रखता है। जब struct
को एक नए चर के लिए असाइन किया गया है, तो इसकी प्रतिलिपि बनाई गई है। नए चर और मूल चर के कारण एक ही डेटा की दो अलग प्रतियां होती हैं। एक प्रतिलिपि में किए गए परिवर्तन अन्य प्रति को प्रभावित नहीं करते हैं।
सामान्य रूप से, classes
का उपयोग अधिक जटिल व्यवहार मॉडल या class
ऑब्जेक्ट के बाद संशोधित करने के उद्देश्य से किया जाता है। Structs
छोटे डेटा संरचनाओं के लिए सबसे उपयुक्त हैं जिनमें मुख्य रूप से डेटा होता है जिसे struct
के बाद संशोधित करने का इरादा नहीं है।
- 1. सी ++ ढेर और ढेर पर स्मृति आवंटित?
- 2. आवंटित परिवर्तनीय संदर्भ कहां है, ढेर में या ढेर में?
- 3. ढेर ढेर और ढेर
- 4. आप ढेर के बजाय ढेर पर स्मृति आवंटित क्यों करना चाहते हैं?
- 5. ढेर/ढेर पर कक्षा के सदस्यों का आवंटन?
- 6. ढेर वास्तव में एक ढेर है?
- 7. फिक्स्ड लंबाई ढेर संरचना
- 8. ढेर और ढेर पर स्मृति स्थान पैटर्न
- 9. ढेर पर या ढेर पर संग्रहीत NSStrings हैं और क्या एक
- 10. ढेर के बजाय स्टैक पर नया (जैसे एलोका बनाम मॉलोक)
- 11. सी # structs/वर्ग ढेर/ढेर नियंत्रण?
- 12. क्या ऑब्जेक्ट के सदस्य चर हैं जो ढेर पर स्वचालित रूप से ढेर पर हैं?
- 13. स्ट्रिंग क्लास छोटे तारों के लिए ढेर पर आवंटित?
- 14. क्यूटी - मुख्य विजेट - ढेर या ढेर?
- 15. विंडोज असेंबली ढेर और ढेर?
- 16. रनटाइम पर जेवीएम ढेर आकार सेट करना
- 17. ढेर
- 18. नेट ढेर बनाम विंडोज ढेर
- 19. ढेर पर स्मृति आवंटन के लिए नया ऑपरेटर
- 20. ढेर और संदर्भों पर ऑब्जेक्ट्स
- 21. क्या JVM ढेर स्वैप करता है?
- 22. स्टैक बनाम ढेर पर जावा मेमोरी आवंटन
- 23. क्या एक ढेर-आवंटित वस्तु सी ++ में हो सकती है?
- 24. ढेर
- 25. क्या QObject स्टैक के बीच अंतर करता है और हटाए जाने पर आवंटित बच्चों को ढेर करता है?
- 26. एंड्रॉइड: रनटाइम पर ढेर आकार कैसे बढ़ाएं?
- 27. सी में ढेर पर एक संरचना कैसे बनाएँ?
- 28. ढेर और ढेर आवंटन
- 29. ढेर एक कार्यान्वयन विस्तार है, या नहीं?
- 30. एक ब्लॉक शाब्दिक संदर्भित संपर्क करना चाहिए ढेर-आवंटित ब्लॉकों
अच्छा जवाब जॉन, इस क्षेत्र की जटिलता का स्पष्टीकरण बहुत महत्वपूर्ण है। मुझे अब पता होना चाहिए कि ज्यादातर सॉफ्टवेयर विकास प्रश्नों के लिए बहुत ही कम काला और सफेद जवाब है। – Ash
जॉन, HowManyStackAllocations उदाहरण कोड अच्छा है। लेकिन क्या आप इसे ग्रिड के बजाय स्ट्रक्चर का उपयोग करने के लिए बदल सकते हैं, या एक नया स्ट्रक्चर उदाहरण जोड़ सकते हैं। मुझे लगता है कि फिर सीधे @ केदार के मूल प्रश्न को संबोधित करेंगे। – Ash
Guid पहले से ही एक संरचना है। Http://msdn.microsoft.com/en-us/library/system.guid.aspx मैंने इस प्रश्न के लिए संदर्भ प्रकार नहीं चुना होगा :) –