2009-05-08 13 views
7

स्थैतिक सरणी पर malloc (विफलता पर पूर्ण वापसी के अलावा) का उपयोग करने का क्या फायदा है? निम्नलिखित कार्यक्रम मेरे सभी राम खाएंगे और केवल लूप को असम्बद्ध होने पर स्वैप भरना शुरू कर देंगे। यह दुर्घटनाग्रस्त नहीं है।मुझे malloc() का उपयोग क्यों करना चाहिए जब "char bigchar [1u << 31 - 1];" ठीक काम करता है?

...

#include <stdio.h> 

unsigned int bigint[ 1u << 29 - 1 ]; 
unsigned char bigchar[ 1u << 31 - 1 ]; 

int main (int argc, char **argv) { 
    int i; 
/* for (i = 0; i < 1u << 29 - 1; i++) bigint[i] = i; */ 
/* for (i = 0; i < 1u << 31 - 1; i++) bigchar[i] = i & 0xFF; */ 

    getchar(); 
    return 0; 
} 

...

कुछ परीक्षण और त्रुटि मैं ऊपर पाया के बाद सबसे बड़ा स्थिर सरणी जीसीसी 4.3 के साथ अपने 32-बिट इंटेल मशीन पर अनुमति दी है। क्या यह एक मानक सीमा है, एक कंपाइलर सीमा, या एक मशीन सीमा? जाहिर है, मैं उनमें से कई को जितना चाहूं उतना प्राप्त कर सकता हूं। यह segfault होगा, लेकिन केवल अगर मैं malloc से अधिक पूछने के लिए (और उपयोग करने की कोशिश) पूछता हूं वैसे भी मुझे दे देंगे।

क्या यह निर्धारित करने का कोई तरीका है कि एक स्थिर सरणी वास्तव में आवंटित की गई थी और उपयोग करने के लिए सुरक्षित थी?

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

संपादक की टिप्पणी:1 << 31causes undefined behaviour यदि पूर्णांक 32-बिट है, इसलिए मैं सवाल को संशोधित किया है 1u पढ़ने के लिए। सवाल का इरादा बड़े स्थैतिक बफर आवंटित करने के बारे में पूछना है।

+0

मुझे नहीं लगता कि यह एक डुप्लिकेट है। मैं प्रश्न को फिर से लिखने के लिए संपादित करूंगा। –

उत्तर

14

ठीक है, दो कारणों से वास्तव में के लिए:

  1. पोर्टेबिलिटी की वजह से

    , के बाद से कुछ सिस्टम आप के लिए आभासी स्मृति प्रबंधन से काम नहीं चलेगा।

  2. आपको अनिवार्य रूप से उपयोगी होने के लिए इस सरणी को छोटे हिस्सों में विभाजित करने की आवश्यकता होगी, फिर सभी हिस्सों का ट्रैक रखने के लिए, अंततः जब आप सरणी के कुछ हिस्सों को "मुक्त" करना शुरू करेंगे आवश्यकता है कि आप memory fragmentation की समस्या को दबाएंगे।

तुम सब स्मृति प्रबंधन कार्यक्षमता का एक बहुत लागू करने पहुंच जाएंगे के सभी पोर्टेबिलिटी का लाभ बिना (वास्तव में काफी malloc reimplementing)।

इसलिए कारण हैं: स्मृति प्रबंधन कैप्सूलीकरण और मानकीकरण के माध्यम से

  • कोड पोर्टेबिलिटी।

  • कोड पुन: उपयोग के माध्यम से व्यक्तिगत उत्पादकता वृद्धि।

5

इसे कस्टम मेमोरी प्रबंधन कहा जाता है, मुझे लगता है। आप ऐसा कर सकते हैं, लेकिन आपको स्मृति की उस हिस्से को स्वयं प्रबंधित करना होगा। आप इस खंड पर चिंतित अपने स्वयं के मॉलोक() लिखना बंद कर देंगे।

10

मॉलोक के साथ आप अपनी सरणी को बढ़ा सकते हैं और सिकुड़ सकते हैं: यह गतिशील हो जाता है, इसलिए आप जो भी चाहते हैं उसके लिए आप आवंटित कर सकते हैं।

+0

बिल्कुल। आम तौर पर यह उन एरे घोषित करने के लिए समझ में आता है जिन्हें आप जानते हैं कि आपको आवश्यकता होगी, और स्टोरेज के लिए मॉलोक का उपयोग करने के लिए जिसे केवल रनटाइम पर ही निर्धारित किया जा सकता है। – alexis

11
+0

हाहा, मैं आपको इस जवाब में निवेश किए जाने के लिए पहले से ही +1 दूंगा: पी –

2

के बारे में:

कुछ परीक्षण और त्रुटि मैं ऊपर सबसे बड़ा स्थिर सरणी के साथ अपने 32-बिट इंटेल मशीन पर अनुमति दी है पाया के बाद जीसीसी 4.3।क्या यह मानक सीमा, एक कंपाइलर सीमा, या मशीन सीमा है?

एक ऊपरी सीमा इस बात पर निर्भर करेगी कि 4 जीबी (32-बिट) आभासी पता स्थान उपयोगकर्ता-स्थान और कर्नेल-स्पेस के बीच कैसे विभाजित होता है। लिनक्स के लिए, मेरा मानना ​​है कि सबसे आम विभाजन योजना में उपयोगकर्ता-अंतरिक्ष के लिए 3 जीबी रेंज और कर्नेल-स्पेस के लिए 1 जीबी रेंज के पते हैं। विभाजन कर्नेल बिल्ड-टाइम, 2 जीबी/2 जीबी और 1 जीबी/3 जीबी विभाजन पर भी कॉन्फ़िगर करने योग्य है। जब निष्पादन योग्य लोड किया जाता है, तो वर्चुअल एड्रेस स्पेस को प्रत्येक ऑब्जेक्ट के लिए आवंटित किया जाना चाहिए, भले ही असली मेमोरी को वापस करने के लिए आवंटित किया गया हो।

2

आप एक विशाल संदर्भ में उस विशाल सरणी को आवंटित करने में सक्षम हो सकते हैं, लेकिन दूसरों को नहीं। उदाहरण के लिए, यदि आपकी सरणी एक संरचना का सदस्य है और आप संरचना को पास करना चाहते हैं। कुछ वातावरण में संरचना आकार पर 32K सीमा होती है।

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

1

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

2

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

फ़ंक्शन के दायरे से बाहर निकलने के बाद आप स्टैक मेमोरी को "रख" नहीं सकते हैं, यह हमेशा मुक्त होता है। इसलिए आपको पता होना चाहिए कि संकलन समय पर आप कितनी मेमोरी का उपयोग करेंगे।

जो तब तक कितने int foo [1 < < 2 9] के लिए उबलता है। चूंकि पहला व्यक्ति पूरी मेमोरी लेता है (32 बिट पर) और होगा (लेटे: 0x000000) दूसरा 0xffffffff या thereaobout को हल करेगा। तब तीसरा क्या हल करेगा? कुछ 32 बिट पॉइंटर्स व्यक्त नहीं कर सकते हैं। (याद रखें कि स्टैक आरक्षण आंशिक रूप से संकलित समय पर आंशिक रूप से संकलित होते हैं, आंशिक रूप से रनटाइम, ऑफ़सेट के माध्यम से, जब आप इस या उस चर को आवंटित करते हैं तो स्टैक ऑफसेट को कितना दूर धक्का दिया जाता है)।

तो जवाब बहुत अधिक है कि एक बार आपके पास int foo [1 < < 2 9] आपके पास अन्य स्थानीय स्टैक चर के साथ फ़ंक्शंस की कोई उचित गहराई नहीं हो सकती है।

+0

मुझे इसे दो बार पढ़ना पड़ा लेकिन आप 32-बिट पॉइंटर की सीमा के बारे में एक अच्छा बिंदु बनाते हैं। मैंने पाया कि मैं एक सीजीएफॉल्ट के बिना दो 1 << 31-1 आकार के सरणी भर सकता हूं, और यह सभी संभावित पॉइंटर्स की पूर्ण गणना शून्य से कम है। इसका मतलब है कि मैं 0x4,0x8 और अन्य स्थानों पर लिख रहा था जहां यह सामान्य रूप से segfaults। मुझे आश्चर्य है कि इस प्रयोग में कर्नेल के साथ क्या हुआ। –

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