2010-01-08 18 views
13

इसलिए सी ++ में यह बहुत आसान है। आप ढेर पर आवंटित किए जाने वाले वर्ग/संरचना को चाहते हैं, नया उपयोग करें। यदि आप इसे ढेर पर चाहते हैं, तो नए का उपयोग न करें।सी # structs/वर्ग ढेर/ढेर नियंत्रण?

सी # में हम हमेशा नए कीवर्ड का उपयोग करते हैं, और इस पर निर्भर करता है कि यह एक संरचना या कक्षा है या तो इसे ढेर या ढेर पर आवंटित किया गया है (structs ढेर पर जाते हैं, ढेर तक कक्षाएं) - और कुछ अनुप्रयोगों में डिजाइन को बदलते समय एक बड़ा प्रदर्शन अंतर हो सकता है जैसे कि केवल वे वस्तुएं ही ढेर पर जाती हैं जो वास्तव में वहां होती है।

मुझे आश्चर्य है कि क्या यह नियंत्रित करने का एक सीधा तरीका है कि किसी ऑब्जेक्ट को आवंटित किया जाता है चाहे इसे संरचना या कक्षा के रूप में घोषित किया गया हो? मुझे पता है कि ढेर पर जाने के लिए मूल्य प्रकार (structs) को बॉक्स किया जा सकता है (लेकिन मुक्केबाजी/अनबॉक्सिंग एक प्रदर्शन लागत पर आता है)। क्या ढेर पर कक्षा आवंटित करने का कोई तरीका है?

इसके अलावा, क्या कच्ची मेमोरी आवंटित करने और सी ++ में प्लेसमेंट जैसे कुछ का उपयोग करने के लिए कोई तंत्र है? मुझे पता है कि यह प्रबंधित होने के विचार से टूटता है - लेकिन यदि आप अपने कस्टम मेमोरी प्रबंधन का उपयोग कर सकते हैं तो यह एक बड़ा प्रदर्शन अंतर कर सकता है।

मुझे इसकी सुविधा के लिए सी # पसंद है, क्योंकि यह कचरा कलेक्टर और अन्य चीजों के लिए है - लेकिन कभी-कभी, किसी एप्लिकेशन की बाधा पर काम करते समय, यह वास्तव में क्या हो रहा है पर अधिक नियंत्रण रखने के लिए वांछनीय होना चाहिए।

कोई युक्ति/संकेत :) का स्वागत करते हैं

संपादित करें: प्रदर्शन उदाहरण:

struct Foo1 
{ 
    public int i; 
    public float f; 
    public double d; 
} 

struct Foo2 
{ 
    public Foo1[] bar; 

    public void Init(){ 
     bar = new Foo1[100]; 
     for (int i = 0; i < 100; i++) 
      bar[i] = new Foo1(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     DateTime time = DateTime.Now; 
     Foo2[] arr = new Foo2[1000000]; 
     for (int i = 0; i < 1000000; i++) 
     { 
      arr[i] = new Foo2(); 
      arr[i].Init(); 
     } 

     Console.WriteLine((DateTime.Now - time).TotalMilliseconds); 
    } 
} 

इस पर अमल करने के लिए अपने मशीन पर 1.8 सेकंड लेता है (ध्यान दें कि वास्तव में केवल आवंटन पर जा रहा है - कोई पैरामीटर गुजर)

यदि फ़ू 1 को संरचना से कक्षा में बदल दिया गया है, तो निष्पादन 8.9 सेकेंड लगता है! यह पांच गुना धीमा है

+3

आपको क्या लगता है कि ढेर बनाम ढेर पर ऑब्जेक्ट आवंटित करने के बीच एक * विशाल * प्रदर्शन अंतर है? – LBushkin

+0

मैंने देखा कि जब मैंने एक 3 डी गेम के लिए भौतिकी सॉल्वर लागू किया था - मैं ऑब्जेक्ट आवंटित किए गए कार्यों से जुड़े सावधानीपूर्वक बदलकर और – Mat

+0

में वस्तुओं को कैसे पारित कर सकता हूं, आप प्रदर्शन को काफी हद तक अनुकूलित कर सकते हैं। आप जानते हैं कि ढेर और ढेर अनिवार्य रूप से हैं स्मृति का एक ही ब्लॉक (एक तरफ कैशिंग), आवंटन एक सूचक है जो आप आधार के रूप में संदर्भित करते हैं। क्षमा करें, क्लासिक स्टैक/ढेर को साफ़ करने के लिए अनिवार्य रूप से स्मृति का एक ही ब्लॉक – GrayWizardx

उत्तर

8

सामान्य मामले में यह सच है कि वस्तुओं को हमेशा ढेर पर आवंटित किया जाता है, सी # आपको भारी इंटरऑप के लिए पॉइंटर स्तर पर या बहुत उच्च प्रदर्शन महत्वपूर्ण कोड के लिए छोड़ देता है।

unsafe ब्लॉक में, आप स्टैक पर ऑब्जेक्ट आवंटित करने के लिए stackalloc का उपयोग कर सकते हैं और पॉइंटर्स के रूप में उनका उपयोग कर सकते हैं।

उनके उदाहरण के शब्दों में:

// cs_keyword_stackalloc.cs 
// compile with: /unsafe 
using System; 

class Test 
{ 
    public static unsafe void Main() 
    { 
     int* fib = stackalloc int[100]; 
     int* p = fib; 
     *p++ = *p++ = 1; 
     for (int i=2; i<100; ++i, ++p) 
     *p = p[-1] + p[-2]; 
     for (int i=0; i<10; ++i) 
     Console.WriteLine (fib[i]); 
    } 
} 

नोट तथापि कि आप एक पूरे विधि असुरक्षित घोषित करने के लिए की जरूरत नहीं है, तो आप सिर्फ यह करने के लिए एक unsafe {...} ब्लॉक का उपयोग कर सकते हैं।

+0

की घोषणा पर नहीं जो मैं ढूंढ रहा था =) धन्यवाद! – Mat

+1

ध्यान दें कि इसके लिए कुछ विशेष अनुमतियों की आवश्यकता है, इसलिए यदि आप पूर्ण कोड वातावरण से कम में अपना कोड चलाते हैं, तो आप परेशानी में भाग ले सकते हैं। इसका एक उदाहरण सिल्वरलाइट है। – Blindy

+0

क्या आपका मतलब था "सामान्य मामले में यह सच है कि वस्तुओं को हमेशा * ढेर * पर आवंटित किया जाता है?" –

6

आपकी व्याख्या किस प्रकार के प्रकार बनाम संदर्भ प्रकार जाती है (स्टैक वी। ढेर) पूरी तरह से सही नहीं है।

स्ट्रक्चर को ढेर पर भी आवंटित किया जा सकता है यदि वे संदर्भ प्रकार के सदस्य हैं उदाहरण के लिए। या यदि आपने ऑब्जेक्ट संदर्भ के माध्यम से उन्हें पास करते समय उन्हें बॉक्स किया है।

आपको http://www.yoda.arachsys.com/csharp/memory.html पढ़ना चाहिए ताकि वास्तव में विभिन्न प्रकार आवंटित किए जाने की बेहतर समझ प्राप्त हो सके।

एक अलग नोट पर, नेट में, आपको वास्तव में कोई प्रकार आवंटित नहीं किया जाना चाहिए - जैसे एरिक लिपर्ट लिखते हैं: the stack is an implementation detail। आप कैसे प्रकार पारित होते हैं (मूल्य, संदर्भ, आदि) के अर्थशास्त्र को समझने से बेहतर हैं।

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

से संबंधित होने का यह सबसे महत्वपूर्ण मुद्दा नहीं है। आपको यह तय करना चाहिए कि इस प्रकार के पास पास-दर-मूल्य अर्थशास्त्र होना चाहिए या नहीं। यदि ऐसा नहीं होता है - तो शायद यह एक संदर्भ प्रकार होना चाहिए।

+0

पर एक्सएनए/नियमित सी # कोड पर भी लागू होता है मान लें कि आप कुछ ऑब्जेक्ट टाइप की एक बड़ी सरणी बनाते हैं। वैसे भी ऐरे ढेर में जायेगा। हालांकि - मेरी समझ के बाद - यदि ऑब्जेक्ट टाइप एक संरचना है, तो पूरी चीज ढेर पर आकस्मिक स्मृति (डेटा का एक समूह - या शायद कार्यान्वयन के आधार पर कुछ विभाजन) में आवंटित की जाएगी। हालांकि - यदि यह एक वर्ग है, तो सरणी के प्रत्येक तत्व को ढेर पर भी आवंटित किया जाएगा - आवंटन के लिए अधिक समय लेना और कचरा संग्रहण धीमा बनाना – Mat

+0

@Mat: तथ्य यह है कि ढेर पर आवंटित सरणी एक कार्यान्वयन विस्तार है। तथ्य यह है कि यह संदर्भों की एक सरणी है (यानी पॉइंटर्स, हमारे लिए सी ++ लोग) हालांकि नहीं है। –

+0

@ पावेल - बिल्कुल यही मेरा मतलब है (मुझे परवाह नहीं है कि सरणी ही ढेर पर है, चूंकि ढेर पर एक ही आवंटन प्रत्येक तत्व के लिए जितना आवंटन नहीं करता है) - तो मुझे लगता है कि यह वांछनीय है उपयोग पर रेफरेंसटाइप/वैल्यूटाइप व्यवहार का निर्णय लेने के लिए, और कक्षा/संरचना – Mat

1

इसके बारे में चिंता न करें - आपका सिर अभी भी सी/सी ++ दुनिया में है जहां यह चीजें कहां जा सकती है। सीएलआर टीम में वास्तव में स्मार्ट लोगों का एक गुच्छा है जो इस दिन जादुई तेज़ बनाने के बारे में चिंता करते हुए पूरे दिन बिताते हैं।

C# और स्मृति के उपयोग आमतौर पर दुर्घटनाओं के छोटे वस्तु की बहुत सारी बनाने के साथ assocaited में कुछ gotchas रहे हैं

वहाँ एक memprofiler कि तुम्हें दिखाता है (कर स्ट्रिंग = स्ट्रिंग + एक पाश में अन्य स्ट्रिंग एक क्लासिक है) क्या हो रहा है, तो क्या तुम सच में लगता है कि तुम एक पर्फ़ स्मृति प्रबंधन की वजह से समस्या आ रही है

मैं प्रदर्शन तीव्र कोड के बहुत सारे लिखा है सी # में (ग्राफिक्स ग्राहकों, नेटवर्क सर्वर प्रतिपादन) और था इस

+0

लेकिन विशेष रूप से ग्राफिक्स प्रतिपादन में, यह मीट एक बड़ा अंतर बनाता है। उदाहरण के लिए यदि एक कण प्रणाली बहुत धीमी हो जाएगी यदि प्रत्येक कण (यहां तक ​​कि जब किसी सरणी में संग्रहीत किया जाता है और मृत्यु पर पुन: उपयोग किया जाता है) को ढेर पर आवंटित किया जाता है क्योंकि स्मृति के एक गुच्छा में आवंटित होने के विपरीत – Mat

+0

कण की एक बड़ी सरणी बनाते हैं structs (जैसा कि अन्य पोस्टर इंगित करते हैं, आप केवल जगह पर ही ढांचे को रख सकते हैं)। आप मेमोरी – pm100

+0

मेमोरी के एक बड़े संक्रामक ब्लॉक के साथ समाप्त हो जाएंगे - लेकिन मुद्दा यह है कि कण के लिए कोड लिखा जाने पर यह निर्णय लिया जाना चाहिए। यदि आप किसी पुस्तकालय से कुछ वर्ग का उपयोग करना चाहते हैं, तो आपके पास एक आकस्मिक ब्लॉक – Mat

1

से किसी के बारे में चिंता करने की कभी नहीं सी # में structs और कक्षाओं को देखने का यह गलत तरीका है। सी # में एक संरचना और कक्षा के बीच का अंतर यह नहीं है कि इसे आवंटित किया गया है, लेकिन कॉपी अर्थशास्त्र। एक संरचना में मूल्य अर्थशास्त्र है और एक वर्ग में संदर्भ अर्थशास्त्र है। सी ++ प्रोग्रामर इस में और अधिक पढ़ते हैं, क्योंकि इन्हें स्टैक पर ऑब्जेक्ट्स के लिए इस्तेमाल किया जाता है जिसमें मूल्य अर्थशास्त्र और संदर्भ अर्थशास्त्र वाले ढेर पर ऑब्जेक्ट होते हैं।

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

+0

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

+0

मैं यह नहीं कह रहा हूं कि एक वर्ग और संरचना के बीच चयन प्रतिलिपि को नियंत्रित करने का एकमात्र तरीका है। मैं कह रहा हूं कि वर्ग/संरचना प्रतिलिपि नीति के बारे में नहीं, प्रतिलिपि प्रतिलिपि के बारे में है। आप किसी विशेष रनटाइम के खिलाफ प्रदर्शन को अलग-अलग आवंटित करने के लिए इसे राजी करके बदल सकते हैं, लेकिन यह कार्यान्वयन निर्भर है। यदि आप प्रदर्शन के लिए अनुकूलित कर रहे हैं तो कौन सा ठीक है। जिन मामलों में यह वास्तव में एक फर्क पड़ता है, वे शायद आपके विचार से दुर्लभ हैं। – Niall

+0

लेकिन यह मेरा सवाल था - मेरी समस्या यह है कि मुझे कॉपी सेमेन्टिक्स को मनाने के लिए टूल मिल गए हैं, लेकिन मेरे पास आवंटन व्यवहार को मनाने के लिए टूल नहीं हैं। और वह कक्षा/संरचना आवंटन नीति के बारे में नहीं है - उदाहरण के लिए इस एमएसडीएन लेख को पढ़ें: http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx "जब आप कॉल करते हैं एक वर्ग पर नया ऑपरेटर, इसे ढेर पर आवंटित किया जाएगा। हालांकि, जब आप एक संरचना को तत्काल बनाते हैं, तो यह ढेर पर बनाया जाता है। इससे प्रदर्शन लाभ मिलेगा। " – Mat

2

new कीवर्ड द्वारा बेवकूफ मत बनो, यह structs के लिए वैकल्पिक है।

सी # में एक प्रबंधित दुनिया है जहां आप कचरा कलेक्टर और टाइप-सेफ्टी का आनंद लेते हैं और कई मेमोरी विवरणों के बारे में चिंता नहीं करते हैं। ढेर/ढेर अंतर अप्रासंगिक है, यह प्रति-अर्थशास्त्र के बारे में है।

उन दुर्लभ मामलों के लिए जहां आप नियंत्रण चाहते हैं, असली पॉइंटर्स और सब कुछ के साथ सी # का असुरक्षित (अप्रबंधित) हिस्सा है।

लेकिन सी ++ में सी # की तुलना में चीजों की लागत सी # में भिन्न है इसलिए भूत, अप्रबंधित, अल्पकालिक वस्तुओं का शिकार बहुत सस्ता नहीं है। और संकलक ढेर पर छोटे सरणी को अनुकूलन के रूप में आवंटित कर सकते हैं, आप यह बताने में सक्षम नहीं होंगे और न ही आपको परवाह करना चाहिए।

+0

लेकिन structs और कक्षाओं के लिए आवंटन समय में उल्लेखनीय प्रदर्शन अंतर है - इसलिए यह तय करना अच्छा होगा कि आवंटन समय आवंटित किया जाए, और वास्तविक वर्ग – Mat

+0

लिखते समय नहीं, "आपका नया" क्या मतलब है ... structs के लिए वैकल्पिक है "? किस संदर्भ में? –

+0

मुझे लगता है कि उनका मतलब है कि structs के लिए, डिफ़ॉल्ट कन्स्ट्रक्टर स्वचालित रूप से बुलाया जाता है, बिना कीवर्ड के भी। हालांकि, कक्षाओं के लिए वेरिएबल एक शून्य सूचक होगा जब तक कि एक कन्स्ट्रक्टर को स्पष्ट रूप से बुलाया नहीं जाता है (नया उपयोग करके) – Mat

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