मुक्त कैसे जानता है कि मुक्त करने के लिए कितना है?


384

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


इसी तरह का सवाल: stackoverflow.com/questions/851958/… (हालाँकि मैं कहूँगा कि यह बिलकुल डुप्लिकेट नहीं है)
जॉन कार्टर

साथी प्रणाली यह करने के लिए एक और तरीका है कि सूचक के आधार पर पता लगा सकते हैं, प्रत्येक ब्लॉक में भूमि के ऊपर के बिना है।
एविलटाइच

यह पोस्ट इसे अच्छी तरह से समझाती है: stackoverflow.com/questions/1957099/…
जीशान महमूद

जवाबों:


348

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

जब आप कॉल करते हैं free(), तो यह पता लगाने के लिए अतिरिक्त जानकारी को देखता है कि ब्लॉक कितना बड़ा है।


44
FYI करें, उदाहरण के लिए BSD को malloc_size()एक malloc()एड पॉइंटर से ब्लॉक आकार को मज़बूती से एक्सेस करना है । लेकिन कोई विश्वसनीय, पोर्टेबल तरीका नहीं है।
लालाटो

50
मुझे लगता है कि यह कहना महत्वपूर्ण है कि यह अतिरिक्त सूचना ब्लॉक लौटे पॉइंटर से पहले स्थित है।
जॉर्ज शॉर्ली

39
@gs कार्यान्वयन-निर्भर है। लेकिन, हाँ, यह वह जगह है जहाँ यह आमतौर पर है।
फालिना

31
क्या आप हॉरर की कल्पना कर सकते हैं यदि free()प्रोग्रामर को सही ढंग से रिपोर्ट करने के लिए आवश्यक है कि malloc()ब्लॉक कितना बड़ा था? मेमोरी लीक काफी खराब है जैसा कि यह है।
मुसिएनेसिस

35
वह जानकारी क्यों malloc()और किसके लिए उपलब्ध है free(), लेकिन आपको किसी सरणी का आकार संग्रहीत करना होगा? blockSize(ptr)अगर वे वैसे भी जानकारी संग्रहीत कर रहे हैं तो वे ऐसा कुछ क्यों नहीं कर पाएंगे ?
corsiKa

144

सी मेमोरी आवंटन कार्यों के अधिकांश कार्यान्वयन प्रत्येक ब्लॉक के लिए या तो इन-लाइन या अलग से लेखांकन जानकारी संग्रहीत करेंगे।

एक विशिष्ट तरीका (इन-लाइन) वास्तव में एक हेडर और आपके द्वारा मांगी गई मेमोरी दोनों को आवंटित करना है, कुछ न्यूनतम आकार के लिए गद्देदार। उदाहरण के लिए, यदि आपने 20 बाइट्स मांगे हैं, तो सिस्टम 48-बाइट ब्लॉक आवंटित कर सकता है:

  • 16-बाइट हेडर जिसमें आकार, विशेष मार्कर, चेकसम, अगले / पिछले ब्लॉक और इतने पर पॉइंटर्स हैं।
  • 32 बाइट्स डेटा क्षेत्र (आपके 20 बाइट्स 16 के कई के लिए गद्देदार)।

फिर आपको दिया गया पता डेटा क्षेत्र का पता होता है। फिर, जब आप ब्लॉक को मुक्त करते हैं, freeतो बस आप जो पता देते हैं, उसे ले लेंगे और यह मानते हुए कि आपने उस पते या उसके आस-पास मेमोरी नहीं भरी है, उसके तुरंत पहले की लेखा जानकारी की जाँच करें। रेखीय रूप से, जो की तर्ज पर होगा:

 ____ The allocated block ____
/                             \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
          ^
          |
          +-- The address you are given

हेडर के आकार को ध्यान में रखें और पैडिंग पूरी तरह से कार्यान्वयन परिभाषित है (वास्तव में, पूरी बात कार्यान्वयन-परिभाषित (ए) है लेकिन इन-लाइन अकाउंटिंग विकल्प एक आम है)।

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

पैडिंग (आवंटन को और अधिक कुशल बनाने के लिए) यही कारण है कि आप कभी-कभी समस्याओं के कारण के बिना अपने अनुरोधित स्थान के अंत से थोड़ा आगे लिख सकते हैं (फिर भी, ऐसा न करें, यह अपरिभाषित व्यवहार है और, सिर्फ इसलिए कि यह कभी-कभी काम करता है, ' टी का मतलब यह करना ठीक है)।


(ए) मैंने mallocएम्बेडेड सिस्टम के कार्यान्वयन को लिखा है, जहां आपको 128 बाइट्स मिले हैं, चाहे आपने जो भी पूछा हो (जो कि सिस्टम में सबसे बड़ी संरचना का आकार था), यह मानते हुए कि आपने 128 बाइट्स या उससे कम की मांग की है (अधिक के लिए अनुरोध) एक पूर्ण वापसी मूल्य के साथ मुलाकात की)। एक बहुत ही सरल बिट-मास्क (अर्थात, इन-लाइन नहीं) का उपयोग यह तय करने के लिए किया गया था कि 128-बाइट का हिस्सा आवंटित किया गया था या नहीं।

दूसरों को मैंने विकसित किया है 16-बाइट विखंडू, 64-बाइट्स विखंडू, 256-बाइट विखंडू और 1K विखंडू के लिए अलग-अलग पूल, फिर से बिट-मास्क का उपयोग करके यह तय करने के लिए कि क्या ब्लॉक का उपयोग किया गया था या उपलब्ध थे।

इन दोनों विकल्पों ने लेखांकन जानकारी के ओवरहेड को कम करने mallocऔर free(जब मुक्त होने पर आसन्न ब्लॉकों को जोड़ने की आवश्यकता नहीं है) की गति को बढ़ाने में कामयाब रहे , विशेष रूप से उस वातावरण में महत्वपूर्ण जो हम काम कर रहे थे।


@paxdiablo का मतलब यह है कि मॉलॉक स्मृति के सन्निहित ब्लॉक आवंटित नहीं करता है?
user10678

2
@ user10678, केवल वास्तविक आवश्यकता mallocयह है कि यह आपको देता है, सफल मामले के लिए, स्मृति का एक ब्लॉक कम से कम जितना आपने पूछा था। अलग-अलग ब्लॉक इस बात के संदर्भ में सन्निहित हैं कि आप उनके भीतर तत्वों का उपयोग कैसे करते हैं, लेकिन इस बात की कोई आवश्यकता नहीं है कि ब्लॉक से आने वाले एरेनास बहुत ही अच्छे हैं।
paxdiablo

संबंधित प्रश्न: मॉलॉक / मुक्त की कोई भिन्नता क्यों नहीं है, जहां आप आकार को मुक्त करते समय निर्दिष्ट करते हैं और इसलिए इसे आकार को स्टोर करने की आवश्यकता नहीं है?
user253751

@ user253751, क्योंकि उसके बाद एक और बात आपको पॉइंटर के ऊपर और ऊपर नज़र रखने की आवश्यकता है। यह दोनों अनावश्यक है और खतरनाक: void *x = malloc(200); free(x, 500);है नहीं समाप्त करने के लिए अच्छी तरह से :-) किसी भी मामले में, दक्षता के लिए, जा रहा वास्तविक बफर के आकार बड़ा हो सकता (आप सिर्फ इस पर भरोसा नहीं कर सकते हैं)।
paxdiablo

@paxdiablo यह भी आकार को धारण करने के लिए बर्बाद स्मृति से बचा जाता है।
user253751

47

से comp.lang.cपूछे जाने वाले प्रश्न सूची: कैसे मुक्त पता है कि कितने बाइट्स मुक्त करने के लिए करता है?

मॉलॉक / नि: शुल्क कार्यान्वयन प्रत्येक ब्लॉक के आकार को याद करता है क्योंकि यह आवंटित किया गया है, इसलिए इसे मुक्त करने के बाद आकार को याद दिलाना आवश्यक नहीं है। (आमतौर पर, आकार आवंटित ब्लॉक से सटे संग्रहीत होता है, यही वजह है कि चीजें आमतौर पर बुरी तरह से टूट जाती हैं यदि आवंटित ब्लॉक की सीमाएं थोड़ी अधिक खराब हो जाती हैं)


2
यह एक गैर जवाब है। सवाल बिल्कुल यही है: क्यों मुक्त मज़बूती से ब्लॉक के आकार को देख सकता है, लेकिन अभी तक प्रोग्रामर के लिए कोई फ़ंक्शन उपलब्ध नहीं है जो ऐसा करता है?
बैनांच

यह वास्तव में मॉलोक एपी के लिए एक कार्यान्वयन विवरण है और इस जानकारी को मानक तरीके से (मेरी जानकारी के लिए) वापस पाने के लिए कोई एपीआई नहीं है। "सिस्टम" इसे रिकॉर्ड करता है और उस पर उपयोग करता है free। हो सकता है कि उत्तर आपको संतुष्ट न कर रहा हो, लेकिन मुझे नहीं लगता कि आप अधिक सामान्य रूप से लागू जानकारी के साथ एक प्राप्त करेंगे :-)
jadehaan

6

इस उत्तर को स्थानांतरित किया जाता है कि कैसे नि: शुल्क () पता है कि कितनी मेमोरी को डीलॉलेट करना है? जहाँ मुझे स्पष्ट रूप से एक स्पष्ट डुप्लिकेट प्रश्न का उत्तर देने से रोका गया था। यह उत्तर इस डुप्लिकेट के लिए प्रासंगिक होना चाहिए:


के मामले के लिए malloc, हीप एलोकेटर को आवश्यक विवरण के लिए मूल रिटर्न पॉइंटर की मैपिंग को स्टोर करना होता हैfree बाद में मेमोरी । इसमें आम तौर पर उपयोग में आबंटन के लिए प्रासंगिक जो भी रूप में मेमोरी क्षेत्र के आकार को संग्रहीत करना शामिल है, उदाहरण के लिए कच्चे आकार, या एक बाइनरी ट्री में एक नोड जिसका उपयोग आवंटन को ट्रैक करने के लिए किया जाता है, या उपयोग में मेमोरी "इकाइयों" की एक गिनती।

freeविफल नहीं होगा यदि आप सूचक को "नाम बदलें" या किसी भी तरह से डुप्लिकेट करते हैं। यह हालांकि संदर्भ नहीं गिना गया है, और केवल पहला freeसही होगा। अतिरिक्तfree s "डबल फ्री" त्रुटियां हैं।

freeपिछले mallocs द्वारा लौटाए गए मानों के साथ किसी भी पॉइंटर को अलग करने का प्रयास करना , और जैसा कि अभी तक अप्रकाशित एक त्रुटि है। आंशिक रूप से मुक्त स्मृति क्षेत्रों से लौटना संभव नहीं है malloc


मैंने एक मॉलॉक कॉल द्वारा लौटाए गए पॉइंटर के मूल्य को बदल दिया। और मैंने इसे एक त्रुटि के बिना मुक्त कर दिया। क्यों? यहां देखें: stackoverflow.com/questions/42618390/…
smwikipedia

4

संबंधित नोट पर जीएलआईबी लाइब्रेरी में मेमोरी एलोकेशन फंक्शन्स हैं जो निहित आकार को नहीं बचाते हैं - और फिर आप बस साइज पैरामीटर को फ्री में पास करते हैं। यह ओवरहेड के हिस्से को खत्म कर सकता है।


3

malloc()और free()सिस्टम / कंपाइलर निर्भर हैं इसलिए एक विशिष्ट उत्तर देना मुश्किल है।

अधिक जानकारी इस दूसरे प्रश्न पर


2
वे वास्तव में पुस्तकालय-निर्भर हैं (आमतौर पर सी लाइब्रेरी, जो आमतौर पर ओएस से बहुत निकटता से जुड़ा हुआ है)। संकलक के लिए, वे सिर्फ कार्य कर रहे हैं।
डोनल फेलो

2

ढेर प्रबंधक आवंटित ब्लॉक कहीं से संबंधित है जब आप कहा जाता है स्मृति की मात्रा संग्रहीत malloc

मैंने कभी खुद को लागू नहीं किया, लेकिन मुझे लगता है कि आवंटित ब्लॉक के सामने मेमोरी सही है जिसमें मेटा जानकारी हो सकती है।


3
यह एक संभव कार्यान्वयन है, लेकिन एक ऐसी प्रणाली को तैयार कर सकता है जहां सभी मेमोरी को पूरी तरह से अलग पृष्ठ में एक ही तालिका में ट्रैक किया जाता है, जरूरी नहीं कि मेमोरी पूल से पास कहीं भी आवंटित किया जाए।
अपरिमेय

2

मूल तकनीक को थोड़ा बड़ा ब्लॉक आवंटित करना था और शुरुआत में आकार को स्टोर करना था, फिर एप्लिकेशन को बाकी ब्लॉग दें। अतिरिक्त स्थान एक आकार रखता है और संभवतः पुन: उपयोग के लिए मुक्त ब्लॉकों को एक साथ जोड़ने के लिए लिंक करता है।

हालांकि, उन चालों के साथ कुछ समस्याएं हैं, जैसे कि खराब कैश और मेमोरी प्रबंधन व्यवहार। ब्लॉक में मेमोरी का सही उपयोग अनावश्यक रूप से पृष्ठ की चीजों को करता है और यह गंदे पृष्ठ भी बनाता है जो साझा करने और कॉपी-ऑन-लिखने में जटिल होते हैं।

इसलिए एक अधिक उन्नत तकनीक एक अलग निर्देशिका रखने के लिए है। विदेशी दृष्टिकोण भी विकसित किए गए हैं जहां स्मृति के क्षेत्र एक ही शक्ति-दो आकारों का उपयोग करते हैं।

सामान्य तौर पर, उत्तर है: राज्य रखने के लिए एक अलग डेटा संरचना आवंटित की जाती है।


1

आपके प्रश्न के उत्तरार्ध का उत्तर देने के लिए: हाँ, आप कर सकते हैं, और C में एक सामान्य पैटर्न निम्नलिखित है:

typedef struct {
    size_t numElements
    int elements[1]; /* but enough space malloced for numElements at runtime */
} IntArray_t;

#define SIZE 10
IntArray_t* myArray = malloc(sizeof(intArray_t) + SIZE * sizeof(int));
myArray->numElements = SIZE;

यह छोटी वस्तुओं के लिए उपयोग किए जाने वाले बीएसडी मॉलॉक के लिए एक पूरी तरह से अलग तकनीक है (हालांकि पास्कल शैली सरणियों के निर्माण के लिए यह पूरी तरह से अच्छी तकनीक है)
पीट किर्कम

0

जब हम मॉलॉक कहते हैं तो यह बस आवश्यकता से अधिक बाइट का उपभोग करता है। इस अधिक बाइट की खपत में चेक राशि, आकार और अन्य अतिरिक्त जानकारी जैसी जानकारी होती है। जब हम उस समय फ्री कॉल करते हैं तो यह सीधे उस अतिरिक्त जानकारी पर जाता है, जहां इसका पता लगता है और यह भी पता चलता है कि कितना ब्लॉक फ्री होगा।


0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.