मलोक बनाम नया - अलग-अलग पैडिंग


110

मैं अपनी परियोजना के लिए किसी और के C ++ कोड की समीक्षा कर रहा हूं जो उच्च-प्रदर्शन कंप्यूटिंग के लिए MPI का उपयोग करता है (10 ^ 5 - 10 ^ 6 कोर)। कोड का उद्देश्य विभिन्न आर्किटेक्चर पर विभिन्न मशीनों के बीच संचार की अनुमति देना है। उन्होंने एक टिप्पणी लिखी है जिसमें कहा गया है:

हम सामान्य रूप से उपयोग करेंगे newऔर delete, लेकिन यहां मैं उपयोग कर रहा हूं mallocऔर free। यह आवश्यक है क्योंकि कुछ संकलक डेटा newका उपयोग करते समय अलग-अलग तरीके से पैड करेंगे , जिससे विभिन्न प्लेटफार्मों के बीच डेटा स्थानांतरित करने में त्रुटि हो सकती है। ऐसा नहीं होता है malloc

यह मानक newबनाम mallocप्रश्नों से मुझे ज्ञात किसी भी चीज के साथ फिट नहीं है ।

नए / डिलीट और मॉलोक / फ्री में क्या अंतर है? इस विचार से संकेत मिलता है कि संकलक किसी वस्तु के आकार की गणना अलग-अलग तरीके से कर सकता है (लेकिन तब वह उपयोग करने से अलग क्यों होता है sizeof)।

मॉलॉक और प्लेसमेंट नया बनाम नया एक काफी लोकप्रिय सवाल है, लेकिन केवल उन newकंस्ट्रक्टरों का उपयोग करने के बारे में बात mallocकरता है, जहां यह प्रासंगिक नहीं है।

मॉलोक संरेखण को कैसे समझता है? कहते हैं कि स्मृति को newया तो ठीक से संरेखित करने की गारंटी है या mallocजो मैंने पहले सोचा था वह है।

मेरा अनुमान है कि उसने अतीत में कुछ समय के लिए अपने स्वयं के बग को गलत बताया newऔर mallocउसे घटाया और अलग-अलग मात्रा में पैडिंग दी, जो मुझे लगता है कि शायद सच नहीं है। लेकिन मुझे Google या किसी भी पिछले प्रश्न का उत्तर नहीं मिल रहा है।

मेरी मदद करो, StackOverflow, तुम मेरी ही उम्मीद कर रहे हैं!


33
अकेले विभिन्न SO थ्रेड्स के अनुसंधान के लिए +1!
.मिलिंद

7
+1 आसानी से एक सबसे अच्छी "मदद-खुद-से-मैं-पूछना-दूसरों" मैं हमेशा एक लंबे समय में एसओ पर देखा गया है। काश मैं इसे कुछ और बार बढ़ा पाता।
व्हिज़क्रैग

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

1
वाह मैं इस सवाल के इस लोकप्रिय होने की उम्मीद नहीं कर रहा था! @ लिंडकैंसर, मुझे नहीं लगता कि किसी भी 8-बाइट की सीमा मान ली गई है। दिलचस्प बात हालांकि।
hcarver

1
एक आवंटन विधि का दूसरे पर उपयोग करने का एक कारण यह है कि "कोई और" वस्तु को मुक्त कर रहा है। यदि यह "कोई और" मुफ्त का उपयोग करके ऑब्जेक्ट को हटा देता है, तो आपको मॉलोक का उपयोग करके आवंटित करना होगा। (पैड का एक मुद्दा एक लाल हेरिंग है।)
लिंडनाइकेंटर

जवाबों:


25

IIRC वहाँ एक picky बिंदु है। mallocकिसी भी मानक प्रकार के लिए संरेखित पते को वापस करने की गारंटी है। ::operator new(n)केवल किसी भी मानक प्रकार n से बड़े के लिए संरेखित पते को वापस करने की गारंटी है , और यदि Tकोई वर्ण प्रकार नहीं है , तो new T[n]केवल इसके लिए संरेखित पते को वापस करने की आवश्यकता है T

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

यह ऑब्जेक्ट के भीतर पैडिंग को प्रभावित नहीं करता है, जो जरूरी है कि आपके पास एक ही लेआउट है, भले ही आपने इसे रखी गई मेमोरी को कैसे आवंटित किया हो। इसलिए यह देखना कठिन है कि डेटा ट्रांसफर करने में त्रुटियों में अंतर कैसे हो सकता है।

क्या कोई संकेत है कि उस टिप्पणी के लेखक ने स्टैक पर या ग्लोबल्स में वस्तुओं के बारे में क्या सोचा है, क्या उनकी राय में वे "मॉलोक की तरह गद्देदार" हैं या "नए की तरह गद्देदार"? वह सुराग दे सकता है कि विचार कहां से आया है।

शायद वह उलझन में है, लेकिन हो सकता है कि जिस कोड के बारे में वह बात कर रहा है वह malloc(sizeof(Foo) * n)बनाम के बीच सीधे अंतर से अधिक हो new Foo[n]। शायद यह अधिक पसंद है:

malloc((sizeof(int) + sizeof(char)) * n);

बनाम

struct Foo { int a; char b; }
new Foo[n];

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


संरेखण के बारे में बिंदुओं के लिए धन्यवाद। प्रश्न में डेटा एक चार सरणी है, इसलिए मुझे संदेह है कि यह यहां संरेखण चीज नहीं है, न ही एक संरचनात्मक चीज - हालांकि यह मेरा पहला विचार भी था।
hcarver

5
@Hbcdev: अच्छी तरह से charसरणियों को कभी भी गद्देदार नहीं किया जाता है, इसलिए मैं स्पष्टीकरण के रूप में "उलझन" के साथ रहूँगा।
स्टीव जेसोप

5

आपके सहकर्मी के new[]/delete[]दिमाग में जादू की कुकी हो सकती है (यह वह जानकारी है जो किसी एरे को हटाते समय कार्यान्वयन का उपयोग करता है)। हालांकि, यह एक समस्या नहीं होती अगर पता द्वारा शुरू किए new[]गए आवंटन का उपयोग किया जाता है (जैसा कि आवंटनकर्ता के विरोध में है)।

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


2
यह मैंने पहले सोचा था, "संरचना इसके भागों के योग से अधिक है" समस्या। शायद यह वह जगह है जहां उसका विचार मूल रूप से आया था।
१२:२२ बजे

3

किसी ऑब्जेक्ट का लेआउट इस बात पर निर्भर नहीं कर सकता है कि इसका उपयोग करके आवंटित किया गया था mallocया नहीं new। वे दोनों एक ही तरह के पॉइंटर को लौटाते हैं, और जब आप इस पॉइंटर को अन्य कार्यों में पास करते हैं तो उन्हें पता नहीं चलेगा कि ऑब्जेक्ट कैसे आवंटित किया गया था। sizeof *ptrकी घोषणा पर निर्भर है ptr, न कि यह कैसे सौंपा गया था।


3

मेरे विचार से आप सही है। पैडिंग कंपाइलर द्वारा की जाती है newया नहीं malloc। यदि आप किसी सरणी या संरचना का उपयोग किए बिना newया mallocबिल्कुल भी घोषित नहीं करते हैं तो पेडिंग विचार लागू होंगे । किसी भी मामले में जब मैं देख सकता हूं कि प्लेटफार्मों के बीच कोड को पोर्ट करते समय कैसे अलग-अलग कार्यान्वयन हो सकते हैं newऔर mallocसमस्याएं पैदा कर सकते हैं, तो मैं यह देखने में पूरी तरह से विफल रहता हूं कि वे प्लेटफार्मों के बीच डेटा स्थानांतरित करने में समस्याएं कैसे पैदा कर सकते हैं।


मैंने पहले ही मान लिया था कि आप newएक अच्छे रैपर के रूप में विचार कर सकते हैं , mallocलेकिन यह अन्य उत्तरों से लगता है जो बिल्कुल सच नहीं है। सर्वसम्मति से लगता है कि पैडिंग दोनों के साथ समान होनी चाहिए; मुझे लगता है कि प्लेटफ़ॉर्म के बीच डेटा ट्रांसफर करने में समस्या तभी आती है जब आपका ट्रांसफर मैकेनिज्म त्रुटिपूर्ण हो :)
hcarver

0

जब मैं अपने सादे पुराने डेटा संरचना के लेआउट को नियंत्रित करना चाहता हूं, तो एमएस विज़ुअल कंपाइलर का उपयोग करता हूं #pragma pack(1)। मुझे लगता है कि इस तरह के एक precompiler निर्देश अधिकांश संकलक के लिए समर्थित है, उदाहरण के लिए gcc

यह रिक्त स्थानों के बिना, संरचनाओं के सभी क्षेत्रों को एक के पीछे एक के पीछे संरेखित करने का परिणाम है।

यदि दूसरे छोर पर स्थित प्लेटफॉर्म एक ही है (यानी 1 के पैडिंग के साथ अपनी डेटा विनिमय संरचना को संकलित करता है), तो दोनों तरफ के डेटा को फिर से प्राप्त किया जाता है। इस प्रकार मुझे कभी भी C ++ में मॉलॉक के साथ नहीं खेलना पड़ा।

कम से कम मैंने नए ऑपरेटर को ओवरलोड करने पर विचार किया होगा, क्योंकि यह सीधे सी ++ में मॉलॉक का उपयोग करने के बजाय कुछ मुश्किल काम करता है।


ऐसी कौन सी स्थितियाँ हैं जहाँ आप डेटा संरचना लेआउट को नियंत्रित करना चाहते हैं? बस उत्सुक।
hcarver

और क्या किसी को समर्थन करने वाले pragma packया समान के बारे में पता है ? मुझे लगता है कि यह मानक का हिस्सा नहीं होगा।
hcarver

gcc उदाहरण के लिए इसका समर्थन करता है। मुझे किस परिस्थिति में इसकी आवश्यकता थी: दो अलग प्लेटफॉर्म के बीच बाइनरी डेटा साझा करना: विंडोज़ और पामओएस के बीच, विंडोज और लिनक्स के बीच बाइनरी स्ट्रीम साझा करना। gcc के बारे में लिंक: gcc.gnu.org/oniltocs/gcc/Structure_002dPacking-Pragmas.html
स्टीफन रोलैंड

0

यह मेरा जंगली अनुमान है कि यह बात कहां से आ रही है। जैसा कि आपने बताया, समस्या MPI पर डेटा ट्रांसमिशन के साथ है।

व्यक्तिगत रूप से, मेरी जटिल डेटा संरचनाओं के लिए, जिन्हें मैं MPI पर भेजना / प्राप्त करना चाहता हूं, मैं हमेशा क्रमबद्धता / डीरिआयलाइज़ेशन विधियों को लागू करता हूं, जो वर्णों की एक सरणी से / में पूरी चीज़ को पैक / अनपैक करता है। अब, पैडिंग के कारण हम जानते हैं कि संरचना का आकार उसके सदस्यों के आकार से बड़ा हो सकता है और इस प्रकार किसी को डेटा संरचना के अनपेडेड आकार की गणना करने की भी आवश्यकता होती है, ताकि हमें पता चले कि कितने बाइट भेजे / प्राप्त किए जा रहे हैं।

उदाहरण के लिए, यदि आप std::vector<Foo> Aउक्त तकनीक के साथ MPI को भेजना / प्राप्त करना चाहते हैं , तो परिणामी सरणी का आकार A.size()*sizeof(Foo)सामान्य होना गलत है । दूसरे शब्दों में, प्रत्येक वर्ग जो विधियों को क्रमबद्ध / डिसेरियलाइज़ करता है, को भी एक विधि लागू करनी चाहिए जो सरणी के आकार की रिपोर्ट करती है (या बेहतर तरीके से सरणी को एक कंटेनर में संग्रहीत करती है)। यह बग के पीछे का कारण बन सकता है । एक तरह से या किसी अन्य, हालांकि, इस धागे में बताया गया newबनाम के साथ कुछ नहीं करना है malloc


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

हां, MPI डेटा प्रकारों को परिभाषित करना ऐसा करने का एक और / सही तरीका है। धीरज के बारे में अच्छी बात। हालांकि, मुझे वास्तव में संदेह है कि वास्तविक समूहों पर क्या होगा। वैसे भी, मैंने सोचा कि अगर वे एक ही रणनीति का पालन करते हैं, तो इससे कीड़े पैदा हो सकते हैं ...
mmirzadeh

0

C ++ में: new कीवर्ड का उपयोग कुछ डेटा-स्ट्रक्चर के संबंध में मेमोरी के कुछ विशेष बाइट्स को आवंटित करने के लिए किया जाता है। उदाहरण के लिए, आपने कुछ वर्ग या संरचना को परिभाषित किया है और आप इसके ऑब्जेक्ट के लिए मेमोरी आवंटित करना चाहते हैं।

myclass *my = new myclass();

या

int *i = new int(2);

लेकिन सभी मामलों में आपको परिभाषित डेटाटाइप (वर्ग, संरचना, संघ, इंट, चार आदि ...) की आवश्यकता होती है और केवल मेमोरी के बाइट्स को आवंटित किया जाएगा जो कि इसके ऑब्जेक्ट / चर के लिए आवश्यक है। (यानी, उस डेटाटाइप के गुणक)।

लेकिन मॉलॉक () विधि के मामले में, आप मेमोरी के किसी भी बाइट को आवंटित कर सकते हैं और आपको हर समय डेटा प्रकार निर्दिष्ट करने की आवश्यकता नहीं है। यहाँ आप इसे मल्लोक की कुछ संभावनाओं में देख सकते हैं ():

void *v = malloc(23);

या

void *x = malloc(sizeof(int) * 23);

या

char *c = (char*)malloc(sizeof(char)*35);

-1

मॉलॉक एक प्रकार का फ़ंक्शन है और नया c ++ में c ++ में एक प्रकार का डेटा प्रकार है, अगर हम मॉलॉक का उपयोग करते हैं तो हमें टाइपकास्ट का उपयोग करना चाहिए अन्यथा कंपाइलर आपको त्रुटि देते हैं और यदि हम मेमोरी की आवंटन के लिए नए डेटा प्रकार का उपयोग करते हैं तो हमें कोई आवश्यकता नहीं है टाइपकास्ट करने के लिए


1
मुझे लगता है कि आपको अपने उत्तर को थोड़ा और तर्क देने की कोशिश करनी चाहिए।
कार्लो

यह उन लोगों के प्रश्न को संबोधित करने के लिए नहीं लगता है, जो पैडिंग के साथ अलग-अलग काम कर रहे हैं, जो कि मैं वास्तव में ऊपर पूछ रहा था।
हकार्वर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.