Brk () सिस्टम कॉल क्या करता है?


184

लिनक्स प्रोग्रामर मैनुअल के अनुसार:

brk () और sbrk () प्रोग्राम ब्रेक के स्थान को बदलते हैं, जो प्रक्रिया के डेटा खंड के अंत को परिभाषित करता है।

डेटा सेगमेंट का यहाँ पर क्या मतलब है? क्या यह सिर्फ डेटा खंड या डेटा, बीएसएस और हीप संयुक्त है?

विकी के अनुसार:

कभी-कभी डेटा, बीएसएस और ढेर क्षेत्रों को सामूहिक रूप से "डेटा खंड" के रूप में संदर्भित किया जाता है।

मुझे सिर्फ डेटा खंड के आकार को बदलने का कोई कारण नहीं दिखता है। यदि यह डेटा, बीएसएस और सामूहिक रूप से ढेर है तो यह समझ में आता है क्योंकि हीप को अधिक स्थान मिलेगा।

जो मुझे मेरे दूसरे सवाल पर लाता है। अब तक पढ़े गए सभी लेखों में, लेखक कहता है कि ढेर ऊपर की ओर बढ़ता है और ढेर नीचे की ओर बढ़ता है। लेकिन वे क्या नहीं समझाते हैं कि क्या होता है जब हीप ढेर और ढेर के बीच की सभी जगह घेर लेती है?

यहां छवि विवरण दर्ज करें


1
जब आप अंतरिक्ष से बाहर होते हैं तो आप क्या करते हैं? आप एचडीडी के लिए स्वैप करते हैं। जब आपने अंतरिक्ष का उपयोग किया है, तो आप इसे अन्य प्रकार की जानकारी के लिए जारी करते हैं।
इगोरिस अज़ानोवस

28
@ आईगोरिस: आप भौतिक मेमोरी को भ्रमित कर रहे हैं (जिसे आप वर्चुअल मेमोरी का उपयोग करके आवश्यकतानुसार डिस्क पर स्वैप कर सकते हैं) और पता स्थान । जब आप अपना पता स्थान भरते हैं, तो स्वैपिंग की कोई भी राशि आपको उन पते को बीच में वापस नहीं देगी।
डैनियल प्रीडेन

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

2
@ ब्रायन: ढेर अलग-अलग आकार और संरेखण, मुक्त पूल, आदि के क्षेत्रों से निपटने के लिए एक जटिल डेटा संरचना है। थ्रेड स्टैक हमेशा पूर्ण पृष्ठों के सन्निकट (आभासी पता स्थान में) अनुक्रम होते हैं। ज्यादातर OSes में, एक पेज एलोकेशन है जो स्टैक, हीप, और मेमोरी-मैपेड फ़ाइलों को अंतर्निहित करता है।
बेन वोइगट

2
@ ब्रायन: किसने कहा कि किसी भी "स्टैक" द्वारा हेरफेर किया जा रहा है brk()और sbrk()? ढेर को पृष्ठ आवंटनकर्ता द्वारा प्रबंधित किया जाता है, बहुत निचले स्तर पर।
बेन वोइगट

जवाबों:


231

आपके द्वारा पोस्ट किए गए आरेख में, "ब्रेक" -इस पते द्वारा हेरफेर किया गया है brkऔर sbrk- हीप के शीर्ष पर बिंदीदार रेखा।

आभासी स्मृति लेआउट की सरलीकृत छवि

आपके द्वारा पढ़ा गया प्रलेखन इसे "डेटा खंड" के अंत के रूप में वर्णित करता है क्योंकि पारंपरिक (पूर्व-साझा-लाइब्रेरी, पूर्व-mmap ) में यूनिक्स डेटा खंड ढेर के साथ निरंतर था; प्रोग्राम शुरू होने से पहले, कर्नेल "टेक्स्ट" और "डेटा" ब्लॉक को रैम में एड्रेस शून्य पर लोड करेगा (वास्तव में पता शून्य से थोड़ा ऊपर, ताकि NULL पॉइंटर वास्तव में कुछ भी इंगित नहीं करता) और ब्रेक एड्रेस सेट करें डेटा खंड का अंत। पहले कॉल mallocतब sbrkब्रेक अप को स्थानांतरित करने और डेटा सेगमेंट के शीर्ष और नए, उच्च ब्रेक पते के बीच में हीप बनाने के लिए उपयोग किया जाएगा , जैसा कि आरेख में दिखाया गया है, और बाद का mallocउपयोग इसे ढेर को बड़ा बनाने के लिए उपयोग करेगा। जैसा आवश्यक हो।

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

मुझे यकीन नहीं है कि इस चित्र में 512GB नंबर कहाँ से आता है। इसका तात्पर्य 64-बिट वर्चुअल एड्रेस स्पेस से है, जो आपके पास मौजूद बहुत ही सरल मेमोरी मैप के साथ असंगत है। वास्तविक 64-बिट पता स्थान इस तरह दिखता है:

कम सरलीकृत पता स्थान

              Legend:  t: text, d: data, b: BSS

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

ब्रेक अभी भी ढेर की ऊपरी सीमा है। हालाँकि, मैंने जो नहीं दिखाया वह यह है कि काले रंग की स्मृति के दर्जनों स्वतंत्र आवंटन कहीं-कहीं काले रंग में हो सकते हैं, mmapइसके बजाय बनाया गया है brk। (ओएस इन्हें brkक्षेत्र से बहुत दूर रखने की कोशिश करेगा ताकि वे टकराएं नहीं।)


7
विस्तृत विवरण के लिए +1। क्या आप जानते हैं कि क्या mallocअभी भी निर्भर करता है brkया अगर यह mmapअलग मेमोरी ब्लॉक को "वापस देने" में सक्षम होने के लिए उपयोग कर रहा है?
एंडर्स एबेल

18
यह विशिष्ट कार्यान्वयन पर निर्भर करता है, लेकिन IIUC बहुत से वर्तमान में छोटे आवंटन के लिए क्षेत्र का mallocउपयोग करता brkहै और mmapबड़े (कहो,> 128K) आवंटन के लिए व्यक्तिगत एस। उदाहरण के लिए, लिनक्स malloc(3)मैनपेज में MMAP_THRESHOLD की चर्चा ।
zwol

1
वास्तव में एक अच्छी व्याख्या। लेकिन जैसा कि आपने कहा कि स्टैक अब वर्चुअल एड्रेस स्पेस के शीर्ष पर नहीं बैठता है। क्या यह केवल 64 बिट एड्रेस स्पेस के लिए सही है या यह 32 बिट एड्रेस स्पेस के लिए भी सही है। और यदि स्टैक एड्रेस स्पेस के शीर्ष पर बैठता है, तो अनाम मेमोरी मैप्स कहां होता है? क्या यह स्टैक से ठीक पहले वर्चुअल एड्रेस स्पेस में सबसे ऊपर है।
निक

3
@ निखिल: यह जटिल है। अधिकांश 32-बिट सिस्टम उपयोगकर्ता-मोड एड्रेस स्पेस के शीर्ष पर स्टैक लगाते हैं, जो अक्सर पूर्ण पता स्थान का केवल 2 या 3 जी होता है (शेष स्थान कर्नेल के लिए आरक्षित होता है)। मैं वर्तमान में एक के बारे में सोच भी नहीं सकता, लेकिन मैं उन्हें नहीं जानता। अधिकांश 64-बिट CPU वास्तव में आपको पूरे 64-बिट स्थान का उपयोग नहीं करने देते हैं; पते के उच्च 10 से 16 बिट्स को शून्य या ऑल-वन होना चाहिए। स्टैक को आमतौर पर प्रयोग करने योग्य कम पतों के शीर्ष के पास रखा जाता है। मैं आपको एक नियम नहीं दे सकता mmap; यह बेहद ओएस पर निर्भर है।
zwol

3
@RiccardoBestetti यह पता स्थान बर्बाद करता है , लेकिन यह हानिरहित है - 64-बिट वर्चुअल पता स्थान इतना बड़ा है कि यदि आप इसे हर सेकंड गीगाबाइट के माध्यम से जलाते हैं , तो इसे चलाने में आपको अभी भी 500 साल लगेंगे। [१] अधिकांश प्रोसेसर आभासी पते के २ ^ ४ 2 से २ ^ ५३ बिट्स के उपयोग की भी अनुमति नहीं देते हैं (एकमात्र अपवाद मुझे पता है कि हैशेड पेज टेबल मोड में POWER4 है)। यह भौतिक रैम को बर्बाद नहीं करता है; अप्रयुक्त पते राम को नहीं सौंपे जाते हैं।
zwol

26

न्यूनतम रननीय उदाहरण

Brk () सिस्टम कॉल क्या करता है?

गिरी को बताता है कि आप उसे पढ़ने और लिखने के लिए स्मृति के एक सन्निहित भाग को लिखते हैं जिसे ढेर कहा जाता है।

यदि आप नहीं पूछते हैं, तो यह आपको अलग कर सकता है।

इसके बिना brk:

#define _GNU_SOURCE
#include <unistd.h>

int main(void) {
    /* Get the first address beyond the end of the heap. */
    void *b = sbrk(0);
    int *p = (int *)b;
    /* May segfault because it is outside of the heap. */
    *p = 1;
    return 0;
}

के साथ brk:

#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>

int main(void) {
    void *b = sbrk(0);
    int *p = (int *)b;

    /* Move it 2 ints forward */
    brk(p + 2);

    /* Use the ints. */
    *p = 1;
    *(p + 1) = 2;
    assert(*p == 1);
    assert(*(p + 1) == 2);

    /* Deallocate back. */
    brk(b);

    return 0;
}

गिटहब ऊपर

उपरोक्त एक नया पृष्ठ हिट नहीं हो सकता है और बिना सीगफॉल्ट के भी नहीं हो सकता है brk, इसलिए यहां एक अधिक आक्रामक संस्करण है जो 16MiB आवंटित करता है और इसके बिना सीगफॉल्ट की संभावना है brk:

#define _GNU_SOURCE
#include <assert.h>
#include <unistd.h>

int main(void) {
    void *b;
    char *p, *end;

    b = sbrk(0);
    p = (char *)b;
    end = p + 0x1000000;
    brk(end);
    while (p < end) {
        *(p++) = 1;
    }
    brk(b);
    return 0;
}

उबंटू 18.04 पर परीक्षण किया गया।

वर्चुअल एड्रेस स्पेस विज़ुअलाइज़ेशन

इससे पहले brk:

+------+ <-- Heap Start == Heap End

के बाद brk(p + 2):

+------+ <-- Heap Start + 2 * sizof(int) == Heap End 
|      |
| You can now write your ints
| in this memory area.
|      |
+------+ <-- Heap Start

के बाद brk(b):

+------+ <-- Heap Start == Heap End

एड्रेस स्पेस को बेहतर तरीके से समझने के लिए, आपको पेजिंग से खुद को परिचित करना चाहिए: x86 पेजिंग कैसे काम करता है?

हम क्यों की जरूरत है दोनों करते हैं brkऔर sbrk?

brk के साथ लागू किया जा सकता है sbrk + ऑफसेट गणना के , दोनों सिर्फ सुविधा के लिए मौजूद हैं।

बैकएंड में, लिनक्स कर्नेल v5.0 में एक सिंगल सिस्टम कॉल brkहै जिसका उपयोग दोनों को लागू करने के लिए किया जाता है: https://github.com/torvalds/linux/blob/v5.0/arch/x86/entry/syscalls_syscall_64। tbl # L23

12  common  brk         __x64_sys_brk

है brkPOSIX?

brk POSIX हुआ करता था, लेकिन POSIX 2001 में इसे हटा दिया गया, इस प्रकार इसकी आवश्यकता थी _GNU_SOURCE ग्लिबक रैपर तक पहुंचने की ।

परिचय के कारण हटाने की संभावना है mmap , जो एक सुपरसेट है जो कई रेंज को आवंटित करने और अधिक आवंटन विकल्प की अनुमति देता है।

मुझे लगता है कि कोई वैध मामला नहीं है जहां आपको brkइसके बजाय mallocया mmapआजकल का उपयोग करना चाहिए ।

brk बनाम malloc

brk लागू करने की एक पुरानी संभावना है malloc

mmapवर्तमान में लागू करने के लिए वर्तमान में उपयोग किए जाने वाले सभी POSIX सिस्टम की संभावना नए शक्तिशाली रूप से अधिक शक्तिशाली तंत्र है malloc। यहाँ एक न्यूनतम रननेबल mmapमेमोरी आवंटन उदाहरण है

क्या मैं मिश्रण brkऔर मालॉक कर सकता हूं ?

यदि आपके mallocसाथ कार्यान्वित किया जाता है brk, तो मुझे पता नहीं है कि कैसे संभवत: चीजों को उड़ा नहीं सकता है, क्योंकि brkकेवल स्मृति की एक सीमा होती है।

हालाँकि मुझे इसके बारे में कुछ भी पता नहीं चल पाया है, उदाहरण के लिए:

चीजें संभवत: वहीं काम करेंगी जो मुझे लगता है mmapकि संभावना है malloc

यह सभी देखें:

और जानकारी

आंतरिक रूप से, कर्नेल यह तय करता है कि क्या इस प्रक्रिया में बहुत अधिक मेमोरी और इयरमार्क्स मेमोरी पेज हो सकते हैं उस उपयोग के लिए ।

यह बताता है कि ढेर की तुलना कैसे की जाती है: x86 असेंबली में रजिस्टरों पर उपयोग किए जाने वाले पुश / पॉप निर्देशों का क्या कार्य है?


4
चूंकि pटाइप करने के लिए एक पॉइंटर है int, क्या ऐसा नहीं होना चाहिए brk(p + 2);?
जोहान बोले

छोटे नोट: आक्रामक संस्करण के लिए लूप की अभिव्यक्ति संभवतः होनी चाहिए*(p + i) = 1;
lima.sierra

वैसे, हमें brk(p + 2)इसे बढ़ाने के बजाय इसका उपयोग करने की आवश्यकता क्यों है sbrk(2)? क्या वास्तव में brk आवश्यक है?
यी लिन लियू

1
@YiLinLiu मुझे लगता है कि यह एक कर्नेल बैकएंड ( brksyscall) के लिए सिर्फ दो समान सी दृश्य हैं । brkपहले से आवंटित स्टैक को पुनर्स्थापित करने के लिए थोड़ा अधिक सुविधाजनक है।
सिरो सेंटिल्ली 郝海东 冠状 iro i 法轮功 '

1
@CiroSantilli 新疆 iro IC 996ICU 事件 int 4 बाइट्स और int की साइज़ का साइज़ * 4 बाइट्स (एक 32 बिट मशीन पर) के रूप में, मैं सोच रहा था कि इसे सिर्फ 4 बाइट्स द्वारा नहीं मिलना चाहिए (इसके बजाय 8 - (2 * sizeof int))। यह अगले उपलब्ध ढेर भंडारण की ओर इशारा नहीं करना चाहिए - जो 4 बाइट्स दूर होगा (8 नहीं)। अगर मुझे यहाँ कुछ याद आ रहा है तो मुझे सुधारो।
साकेत शरद

10

आप "मॉलॉक ओवरहेड" से बचने के लिए अपने आप का उपयोग कर सकते हैं brkऔर sbrkसभी को हमेशा शिकायत कर सकते हैं। लेकिन आप आसानी से इस विधि का उपयोग नहीं कर सकते हैं, mallocइसलिए यह तभी उचित है जब आपको freeकुछ भी नहीं करना है । क्योंकि तुम नहीं कर सकते। इसके अलावा, आपको किसी भी पुस्तकालय कॉल से बचना चाहिए जो mallocआंतरिक रूप से उपयोग कर सकते हैं । अर्थात। strlenशायद सुरक्षित है, लेकिन fopenशायद नहीं है।

sbrkआप जैसा कहेंगे, वैसे ही कॉल करें malloc। यह वर्तमान ब्रेक के लिए एक पॉइंटर लौटाता है और उस राशि से ब्रेक को बढ़ाता है।

void *myallocate(int n){
    return sbrk(n);
}

जब आप व्यक्तिगत आवंटन को मुक्त नहीं कर सकते हैं (क्योंकि कोई मॉलोक-ओवरहेड नहीं है , तो याद रखें), आप पहले स्थान पर लौटे मूल्य के साथ कॉल करके पूरे स्थान को मुक्त कर सकते हैं , इस प्रकार ब्रॉक को फिर से याद कर सकते हैं ।brksbrk

void *memorypool;
void initmemorypool(void){
    memorypool = sbrk(0);
}
void resetmemorypool(void){
    brk(memorypool);
}

आप इन क्षेत्रों को भी रोक सकते हैं, इस क्षेत्र की शुरुआत के लिए ब्रेक को रिवाइंड करके सबसे हालिया क्षेत्र को छोड़ सकते हैं।


एक और चीज़ ...

sbrkकोड गोल्फ में भी उपयोगी है क्योंकि यह 2 वर्णों से छोटा है malloc


7
-1 क्योंकि: malloc/ freeसबसे निश्चित रूप से (और कर सकते हैं) ओएस को स्मृति वापस दे। वे हमेशा ऐसा नहीं कर सकते हैं जब आप उन्हें चाहते हैं, लेकिन यह आपके उपयोग के मामले के लिए पूरी तरह से संरक्षित किए जाने की बात है। इससे भी महत्वपूर्ण बात यह हैsbrk कि किसी भी कार्यक्रम में नॉनज़ेरो तर्क के साथ कॉल करना असुरक्षित है जो कभी भी कॉल कर सकता है malloc- और लगभग सभी सी लाइब्रेरी फ़ंक्शन को mallocआंतरिक रूप से कॉल करने की अनुमति है । केवल वही जो निश्चित रूप से एसिंक्स-सिग्नल-सुरक्षित फ़ंक्शन नहीं होंगे।
zwol

और "यह असुरक्षित है" से मेरा मतलब है कि "आपका कार्यक्रम दुर्घटनाग्रस्त हो जाएगा।"
zwol

मैंने रिटर्निंग मेमोरी घमंड को दूर करने के लिए संपादन किया है , और आंतरिक रूप से उपयोग करने वाले पुस्तकालय कार्यों के खतरे का उल्लेख किया है malloc
लूजर ने

1
यदि आप फैंसी मेमोरी एलोकेशन करना चाहते हैं, तो या तो यह मॉलॉक के ऊपर, या मिमीप के शीर्ष पर बेस करें। Brk और sbrk को मत छुओ, वे अतीत से अवशेष हैं जो अच्छे से अधिक नुकसान करते हैं (यहां तक ​​कि मैनपेज़ आपको उनके बारे में स्पष्ट रहने के लिए कहते हैं!)
एल्फ

3
यह बेवक़ूफ़ी है। यदि आप बहुत से छोटे आवंटन के लिए मॉलॉक ओवरहेड से बचना चाहते हैं, तो एक बड़ा आवंटन ( मॉलोक या एमएमएपी के साथ करें, न कि सरेक) और अपने आप को बाहर कर दें। यदि आप अपने बाइनरी ट्री के नोड्स को एक सरणी में रखते हैं, तो आप 64b पॉइंटर्स के बजाय 8b या 16b इंडेक्स का उपयोग कर सकते हैं। जब तक आप सभी नोड्स को हटाने के लिए तैयार नहीं हो जाते तब तक किसी भी नोड को हटाने की आवश्यकता नहीं होने पर यह बहुत अच्छा काम करता है । (उदाहरण के लिए तुरंत एक क्रमबद्ध शब्दकोश का निर्माण।) का उपयोग करना sbrkके लिए यह है केवल , कोड गोल्फ के लिए उपयोगी है क्योंकि मैन्युअल का उपयोग कर mmap(MAP_ANONYMOUS)स्रोत-कोड आकार को छोड़कर हर तरह से बेहतर है।
पीटर कॉर्ड्स

3

एक विशेष नामित अनाम निजी मेमोरी मैपिंग है (परंपरागत रूप से डेटा / बीएसएस से परे स्थित है, लेकिन आधुनिक लिनक्स वास्तव में एएसएलआर के साथ स्थान को समायोजित करेगा)। सिद्धांत रूप में, यह आपके द्वारा बनाई जा सकने वाली किसी भी अन्य मैपिंग से बेहतर नहीं है mmap, लेकिन लिनक्स में कुछ अनुकूलन हैं जो इस मानचित्रण के अंत का विस्तार करना संभव है ( brkसिसकॉल का उपयोग करके ) ऊपर की ओर कम लॉकिंग लागत के सापेक्ष जो कि mmapया क्या mremapहोगा। यह mallocमुख्य ढेर को लागू करते समय कार्यान्वयन के लिए आकर्षक बनाता है ।


आप ऊपर की ओर इस मैपिंग के अंत का विस्तार करने के लिए संभव है, हाँ?
zwol

हाँ, ठीक है। उसके लिए माफ़ करना!
आर .. गिटहब स्टॉप हेल्पिंग ICE

0

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


तो क्या brk और sbrk का उपयोग होता है?
Nik

3
@ निखिलरथोद: और / या हुड के तहत malloc()उपयोग करेगा - और आप भी, यदि आप अपने स्वयं के अनुकूलित काम को लागू करना चाहते हैं । brk()sbrk()malloc()
डैनियल Pryden

@ डैनियल प्राइडेन: जब स्टैक और डेटा सेगमेंट के बीच में ढेर और ब्रैक काम कर सकते हैं, जैसा कि ऊपर चित्र में दिखाया गया है। इसके लिए काम के ढेर अंत में होना चाहिए। क्या मैं सही हू?
निक

2
@ ब्रायन: डैनियल ने कहा कि ओएस स्टैक सेगमेंट का प्रबंधन करता है , स्टैक पॉइंटर का नहीं ... बहुत अलग चीजें। मुद्दा यह है कि स्टैक सेगमेंट के लिए कोई sbrk / brk syscall नहीं है - लिनक्स स्वचालित रूप से स्टैक सेगमेंट के अंत में लिखने के प्रयासों पर पेज आवंटित करता है।
जिम बाल्टर

1
और ब्रायन, आपने केवल आधे प्रश्न का आधा उत्तर दिया। यदि कोई स्थान उपलब्ध न हो तो स्टैक पर पुश करने का प्रयास करने पर दूसरा आधा भाग होता है ... आपको एक विभाजन दोष मिलता है।
जिम बैल्टर

0

ढेर को प्रोग्राम के डेटा सेगमेंट में अंतिम स्थान पर रखा गया है। brk()का उपयोग हीप के आकार को बदलने (विस्तार) के लिए किया जाता है। जब ढेर नहीं बढ़ सकता है तो कोई भी mallocकॉल विफल हो जाएगी।


तो आप कह रहे हैं कि इंटरनेट के सभी आरेख, जैसे मेरे प्रश्न में गलत हैं। यदि संभव हो तो आप कृपया मुझे एक सही आरेख की ओर संकेत कर सकते हैं।
निक

2
@ निखिल ध्यान रखें कि उस आरेख का शीर्ष स्मृति का अंत है। जैसे ही स्टैक बढ़ता है स्टैक का शीर्ष आरेख पर नीचे की ओर बढ़ता है। ढेर का शीर्ष आरेख पर ऊपर की ओर बढ़ता है क्योंकि यह विस्तारित होता है।
ब्रायन गॉर्डन

0

डेटा सेगमेंट मेमोरी का वह भाग है जो आपके सभी स्टैटिक डेटा को रखता है, लॉन्च के समय निष्पादन योग्य से पढ़ा जाता है और आमतौर पर शून्य-भरा होता है।


इसमें अनइंस्टाल्यूटेड स्टेटिक डेटा (निष्पादन योग्य में मौजूद नहीं) भी होता है जो कचरा हो सकता है।
लूजर ने

Uninitialized स्थिर डेटा ( .bss) प्रोग्राम प्रारंभ होने से पहले OS द्वारा ऑल-बिट्स-शून्य के लिए प्रारंभ किया जाता है; यह वास्तव में सी मानक द्वारा गारंटी है। कुछ एम्बेडेड सिस्टम परेशान नहीं कर सकते हैं, मुझे लगता है (मैंने कभी नहीं देखा है, लेकिन मैं उस सभी काम नहीं करता हूं)
zwol

@zwol: लिनक्स के पास शून्य-पृष्ठों का संकलन करने का एक विकल्प है mmap, जिसके द्वारा वापस नहीं किया गया है , लेकिन मुझे लगता है .bssकि अभी भी शून्य होगा। बीएसएस स्पेस शायद इस तथ्य को व्यक्त करने का सबसे कॉम्पैक्ट तरीका है कि एक कार्यक्रम कुछ शून्य एरेज़ चाहता है।
पीटर कॉर्ड्स

1
@PeterCordes सी मानक क्या कहता है कि बिना वैरिएबल के घोषित किए गए वैश्विक चरों को शून्य मानकर आरंभिक मान लिया जाता है। एसी कार्यान्वयन जो ऐसे चर को अंदर रखता है.bss शून्य और .bssइसलिए गैर- अनुरूप नहीं होगा। लेकिन कुछ भी एक सी कार्यान्वयन को .bssसभी पर उपयोग करने के लिए मजबूर नहीं करता है या यहां तक ​​कि ऐसी चीज भी है।
zwol

@PeterCordes इसके अलावा, "C कार्यान्वयन" और कार्यक्रम के बीच की रेखा बहुत ही अस्पष्ट हो सकती है, जैसे कि आमतौर पर कार्यान्वयन से कोड का एक छोटा हिस्सा होता है, प्रत्येक निष्पादन योग्य में सांख्यिकीय रूप से जुड़ा होता है, जो पहले चलता है main; यह कोड .bssकर्नेल करने के बजाय क्षेत्र को शून्य कर सकता है , और यह अभी भी अनुरूप होगा।
१०:१६ बजे

0

मैलोक मेमोरी को आवंटित करने के लिए brk सिस्टम कॉल का उपयोग करता है।

शामिल

int main(void){

char *a = malloc(10); 
return 0;
}

इस सरल प्रोग्राम को स्ट्रेस के साथ चलाएं, इसे brk सिस्टम कहेंगे।

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