2011-11-06 2 views
71

शायद यह मंच से मंच तक अलग है, लेकिनmalloc gcc में मानों को 0 में क्यों प्रारंभ करता है?

जब मैं जीसीसी का उपयोग करके संकलित करता हूं और नीचे कोड चलाता हूं, तो मुझे हर बार अपने उबंटू 11.10 में 0 मिलता है।

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    double *a = (double*) malloc(sizeof(double)*100) 
    printf("%f", *a); 
} 

कॉलोक होने के बावजूद मॉलोक ऐसा क्यों व्यवहार करता है?

क्या इसका मतलब यह नहीं है कि मूल्यों को प्रारंभ करने के लिए केवल एक अनचाहे प्रदर्शन ओवरहेड है, भले ही आप इसे कभी-कभी नहीं चाहते हैं?


संपादित करें: ओह, मेरा पिछला उदाहरण initiazling नहीं था, लेकिन "ताजा" ब्लॉक का उपयोग करने के लिए हुआ।

int main() 
{ 
    int *a = (int*) malloc(sizeof(int)*200000); 
    a[10] = 3; 
    printf("%d", *(a+10)); 

    free(a); 

    a = (double*) malloc(sizeof(double)*200000); 
    printf("%d", *(a+10)); 
} 

OUTPUT: 3 
     0 (initialized) 

लेकिन उनका कहना है कि वहाँ एक सुरक्षा कारणों से जब mallocing है उसके लिए धन्यवाद:

क्या मैं ठीक लिए देख रहा था कि ऐसा क्यों यह initializes जब यह एक बड़ी ब्लॉक आवंटित करता था! (इसके बारे में कभी सोचा नहीं)। निश्चित रूप से इसे ताजा ब्लॉक, या बड़े ब्लॉक आवंटित करते समय शून्य पर प्रारंभ करना होगा।

+12

एक और अधिक यथार्थवादी परीक्षण के लिए साथ आउटपुट, आप, आवंटन को मुक्त कराने और उसके बाद फिर आवंटन (संभवतः प्रत्येक कई बार दोहरा) की कोशिश की? सिर्फ इसलिए कि मॉलोक शून्य-प्रारंभिक मेमोरी देता है पहली बार इसका मतलब यह नहीं है कि आप इसे सामान्य रूप से गिन सकते हैं। – user786653

+1

यह भी हो सकता है कि स्मृति ऑपरेटिंग सिस्टम या कुछ द्वारा 0 पर सेट की गई थी और 'malloc' के पास इसके साथ कुछ लेना देना नहीं था। –

+0

[सुरक्षा कारणों से सी में 'malloc' का परिणाम न डालें] (http://stackoverflow.com/q/605845/995714) –

उत्तर

157

लघु उत्तर:

यह नहीं है, यह सिर्फ शून्य अपने मामले में होने वाला है।
(इसके अलावा अपने परीक्षण का मामला नहीं दिखा है कि डेटा शून्य है यह केवल तभी एक तत्व शून्य है पता चलता है।।)


लांग उत्तर:

जब आप malloc() फोन, दो में से एक चीजें घटित होंगी:

  1. यह स्मृति को फिर से आवंटित करता है जो पहले आवंटित किया गया था और उसी प्रक्रिया से मुक्त किया गया था।
  2. यह ऑपरेटिंग सिस्टम से नए पेज (अनुरोधों) का अनुरोध करता है।

पहले मामले में, स्मृति में पिछले आवंटन से डेटा बचे हुए होगा। तो यह शून्य नहीं होगा। छोटे आवंटन करते समय यह सामान्य मामला है।

दूसरे मामले में, स्मृति ओएस से होगी। ऐसा तब होता है जब प्रोग्राम स्मृति से बाहर हो जाता है - या जब आप बहुत बड़े आवंटन का अनुरोध कर रहे होते हैं। (जैसा कि आपके उदाहरण में है)

यहां कैच है: ओएस से आने वाली मेमोरी सुरक्षा कारणों से शून्य हो जाएगी।*

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

* मुझे लगता है कि सी मानक इस बारे में कुछ भी नहीं कहता है। यह कड़ाई से एक ओएस व्यवहार है। तो यह शून्यकरण सिस्टम पर मौजूद हो सकता है या नहीं हो सकता है जहां सुरक्षा चिंता का विषय नहीं है।


इस के लिए एक प्रदर्शन पृष्ठभूमि के कुछ देने के लिए:

@R के रूप में। टिप्पणियों में उल्लेख है, यह शून्य है कि आपको हमेशा use calloc() instead of malloc() + memset() क्यों होना चाहिए। calloc() अलग-अलग memset() से बचने के लिए इस तथ्य का लाभ उठा सकता है।


दूसरी ओर, यह शून्य कभी-कभी प्रदर्शन बाधा होती है। कुछ संख्यात्मक अनुप्रयोगों (जैसे out-of-place FFT) में, आपको स्क्रैच मेमोरी का एक बड़ा हिस्सा आवंटित करने की आवश्यकता है। जो भी एल्गोरिदम करने के लिए इसका इस्तेमाल करें, फिर इसे मुक्त करें।

इन मामलों में, शून्यिंग अनावश्यक है और शुद्ध ओवरहेड की मात्रा है।

मैंने देखा है कि सबसे चरम उदाहरण 48 जीबी स्क्रैच बफर के साथ 70-सेकंड ऑपरेशन के लिए 20-सेकंड शून्यिंग ओवरहेड है। (। मोटे तौर पर 30% भूमि के ऊपर) (दी: मशीन स्मृति बैंडविड्थ की कमी था।)

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

+18

+1। –

+14

लेकिन आप अभी भी शून्य पर भरोसा नहीं कर सकते हैं जब तक कि आप ऐसा नहीं करते (या 'कॉलोक' के साथ, जो ओएस से स्मृति प्राप्त करने के बाद आपके लिए करता है)। –

+0

आपके उत्तर के लिए धन्यवाद। कभी सोचा नहीं कि मॉलोकिंग करते समय सुरक्षा समस्या होगी! – SHH

0

क्या आप जानते हैं कि यह निश्चित रूप से प्रारंभ किया जा रहा है? क्या यह संभव है कि malloc() द्वारा लौटाया गया क्षेत्र केवल शुरुआत में 0 है?

2

मानक यह निर्धारित नहीं करता है कि malloc() मानों को शून्य में प्रारंभ करना चाहिए। यह आपके प्लेटफॉर्म पर होता है कि इसे शून्य पर सेट किया जा सकता है, या यह उस मूल्य को शून्य हो सकता है जब आप उस मान को पढ़ते हैं।

2

आपका कोड यह प्रदर्शित नहीं करता है कि malloc इसकी स्मृति को 0 तक शुरू करता है। प्रोग्राम शुरू होने से पहले ऑपरेटिंग सिस्टम द्वारा किया जा सकता है। शंख देखने के लिए, स्मृति के लिए एक अलग मूल्य लिखें, इसे मुक्त करें, और फिर मॉलोक को कॉल करें। आपको शायद एक ही पता मिलेगा, लेकिन आपको यह जांचना होगा। यदि ऐसा है, तो आप यह देखने के लिए देख सकते हैं कि इसमें क्या है। हमें बताऐ!

20

ओएस आमतौर पर ताजा मेमोरी पेज साफ़ करेगा जो इसे आपकी प्रक्रिया में भेजता है ताकि यह पुरानी प्रक्रिया के डेटा को न देख सके। इसका अर्थ यह है कि पहली बार जब आप एक वैरिएबल (या मॉलोक कुछ) शुरू करते हैं तो यह अक्सर शून्य होगा, लेकिन यदि आपने कभी भी उस स्मृति का पुन: उपयोग किया है (उदाहरण के लिए इसे मुक्त करके और फिर से malloc-ing), तो सभी शर्त बंद हैं।

यह असंगतता ठीक है क्यों अनियंत्रित चर बग खोजने के लिए इतना मुश्किल है।


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

+3

+1 ... सुनिश्चित नहीं है कि "शायद" बोल्ड टेक्स्ट विचार में आवश्यक है ;-) –

15

आप मानते हैं कि malloc() शून्य से शुरू होता है?ऐसा इसलिए होता है कि malloc() पर पहली कॉल sbrk या mmap सिस्टम कॉल पर कॉल करती है, जो ओएस से स्मृति का एक पृष्ठ आवंटित करती है। ओएस को सुरक्षा कारणों से शून्य-प्रारंभिक स्मृति प्रदान करने के लिए बाध्य किया जाता है (अन्यथा, अन्य प्रक्रियाओं से डेटा दिखाई देता है!)। तो आप वहां सोच सकते हैं - ओएस पेज को शून्य करने का समय बर्बाद कर देता है। लेकिन नहीं! लिनक्स में, 'शून्य पृष्ठ' नामक एक विशेष सिस्टम-व्यापी सिंगलटन पृष्ठ होता है और वह पृष्ठ कॉपी-ऑन-लिखित के रूप में मैप किया जाएगा, जिसका अर्थ है कि केवल जब आप वास्तव में उस पृष्ठ पर लिखते हैं, तो ओएस एक और पृष्ठ आवंटित करेगा और इसे शुरू करें। तो मुझे उम्मीद है कि यह प्रदर्शन के बारे में आपके प्रश्न का उत्तर देगा। मेमोरी पेजिंग मॉडल उसी पृष्ठ के एकाधिक मैपिंग की क्षमता का समर्थन करके स्मृति के उपयोग को आलसी के प्रकार की अनुमति देता है और पहले लिखने पर मामले को संभालने की क्षमता का समर्थन करता है।

आप free() कॉल करते हैं, glibc संभाजक अपने नि: शुल्क सूची में क्षेत्र वापस आ जाएगी, और जब malloc() फिर से कहा जाता है, आपको लगता है कि एक ही क्षेत्र मिल सकता है, लेकिन पिछले डेटा के साथ गंदे। आखिरकार, free() सिस्टम कॉल को दोबारा कॉल करके ओएस को स्मृति वापस कर सकता है।

सूचना है कि malloc() पर glibcआदमी पेज सख्ती का कहना है कि स्मृति में अवरोध है तो एपीआई पर "अनुबंध" से, आप कल्पना नहीं कर सकते है कि यह मंजूरी दे दी हो। यहां मूल अंश दिया गया है:

malloc() आकार बाइट आवंटित करता है और आवंटित स्मृति में एक सूचक देता है।
स्मृति साफ़ नहीं है। यदि आकार 0 है, तो malloc() या तो NULL, या एक अद्वितीय सूचक मान देता है जिसे बाद में सफलतापूर्वक पारित किया जा सकता है()।

यदि आप चाहें, तो आप उस दस्तावेज़ीकरण के बारे में अधिक पढ़ सकते हैं यदि आप प्रदर्शन या अन्य दुष्प्रभावों के बारे में चिंतित हैं।

0

कभी कभी पर गिनती किसी भी संकलक कोड है कि कुछ भी करने के लिए स्मृति प्रारंभ हो जाएगा उत्पन्न करने के लिए। malloc बस मेमोरी कुछ जगह नरक के एन बाइट्स के लिए एक सूचक देता है यह भी स्वैप में हो सकता है।

यदि स्मृति की सामग्री महत्वपूर्ण है तो इसे स्वयं शुरू करें।

+4

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

2

gnu.org से:

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

+0

ओपी हालांकि छोटे चरणों में mallocing है। क्या आपके पास उस संदर्भ के बारे में कुछ भी है? – hugomg

13

मैंने 2 समान आवंटन रखने के लिए आपके उदाहरण को संशोधित किया। अब malloc को देखना आसान नहीं है शून्य स्मृति शुरू नहीं करता है।

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    { 
     double *a = malloc(sizeof(double)*100); 
     *a = 100; 
     printf("%f\n", *a); 
     free(a); 
    } 
    { 
     double *a = malloc(sizeof(double)*100); 
     printf("%f\n", *a); 
     free(a); 
    } 

    return 0; 
} 

जीसीसी 4.3.4

100.000000 
100.000000 
+0

मैंने कोशिश की कि आपने क्या किया और यदि मैं केवल 100 बाइट आवंटित करता हूं, भले ही सूचक एक ही पते पर इंगित करता है, तो उस पते का मान अलग है। अगर मैं 400 बाइट्स या उससे अधिक आवंटित करता हूं तो दोनों सूचक मूल्य और स्मृति में मान समान हैं। आपको क्या लगता है कि कारण हो सकता है? –

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