का उपयोग malloc()
और free()
Arduino दुनिया में बहुत दुर्लभ लगता है। इसका उपयोग शुद्ध AVR C में अधिक बार किया जाता है, लेकिन फिर भी सावधानी के साथ।
यह एक बहुत बुरा विचार का उपयोग करना है malloc()
और free()
Arduino के साथ?
का उपयोग malloc()
और free()
Arduino दुनिया में बहुत दुर्लभ लगता है। इसका उपयोग शुद्ध AVR C में अधिक बार किया जाता है, लेकिन फिर भी सावधानी के साथ।
यह एक बहुत बुरा विचार का उपयोग करना है malloc()
और free()
Arduino के साथ?
जवाबों:
एम्बेडेड सिस्टम के लिए मेरा सामान्य नियम केवल malloc()
बड़े बफ़र्स के लिए है और केवल एक बार, कार्यक्रम की शुरुआत में, जैसे, में setup()
। मुसीबत तब आती है जब आप मेमोरी को आवंटित और डी-आवंटित करते हैं। लंबे समय तक चलने वाले सत्र में, स्मृति खंडित हो जाती है और अंततः एक पर्याप्त बड़े मुक्त क्षेत्र की कमी के कारण आवंटन विफल हो जाता है, भले ही कुल मुफ्त स्मृति अनुरोध के लिए पर्याप्त से अधिक हो।
(ऐतिहासिक परिप्रेक्ष्य, रुचि न होने पर छोड़ें): लोडर कार्यान्वयन के आधार पर, रन-टाइम एलोकेशन बनाम कंपाइल-टाइम एलोकेशन (इन्टिहलाइज्ड ग्लोबल्स) का एकमात्र लाभ हेक्स फाइल का आकार है। जब सभी अस्थिर मेमोरी वाले शेल्फ कंप्यूटरों के साथ एम्बेडेड सिस्टम बनाए गए थे, तो प्रोग्राम अक्सर एक नेटवर्क या इंस्ट्रूमेंटेशन कंप्यूटर से एम्बेडेड सिस्टम पर अपलोड किया गया था और अपलोड समय कभी-कभी एक समस्या थी। छवि से शून्य से भरे बफ़र्स को छोड़ना समय को काफी कम कर सकता है।)
यदि मुझे एक एम्बेडेड सिस्टम में गतिशील मेमोरी आवंटन की आवश्यकता है, तो मैं आमतौर पर malloc()
, या अधिमानतः, सांख्यिकीय रूप से आवंटित करता हूं , एक बड़ा पूल और इसे निश्चित आकार के बफ़र्स (या क्रमशः छोटे और बड़े बफ़र्स में से प्रत्येक एक पूल) में विभाजित करता हूं और अपना स्वयं का आवंटन करता हूं / उस पूल से डी-आवंटन। फिर निश्चित बफर आकार तक की किसी भी मेमोरी के लिए हर अनुरोध को उन बफ़र्स में से एक के साथ सम्मानित किया जाता है। कॉलिंग फ़ंक्शन को यह जानने की ज़रूरत नहीं है कि क्या यह अनुरोध से बड़ा है, और बंटवारे और फिर से संयोजन ब्लॉकों से बचने से हम विखंडन को हल करते हैं। बेशक मेमोरी लीक अभी भी हो सकता है अगर कार्यक्रम ने बग आवंटित / डी-आवंटित किया है।
आमतौर पर, जब Arduino रेखाचित्र लिखते हैं, तो आप गतिशील आवंटन ( सी ++ उदाहरणों के साथ malloc
या इसके साथ new
) से बचेंगे, लोग वैश्विक- static
वैरिएबल या स्थानीय (स्टैक) चर का उपयोग करते हैं।
गतिशील आवंटन का उपयोग करने से कई समस्याएं हो सकती हैं:
malloc
/ free
कॉल के बाद ) जहां ढेर वर्तमान में आवंटित स्मृति की वास्तविक मात्रा से बड़ा होता हैज्यादातर स्थितियों में मैंने सामना किया, गतिशील आवंटन या तो आवश्यक नहीं था, या मैक्रोज़ के साथ निम्न कोड नमूने में बचा जा सकता था:
MySketch.ino
#define BUFFER_SIZE 32
#include "Dummy.h"
Dummy.h
class Dummy
{
byte buffer[BUFFER_SIZE];
...
};
बिना #define BUFFER_SIZE
, अगर हम चाहते थे कि Dummy
वर्ग एक गैर-निश्चित buffer
आकार का हो, तो हमें निम्नानुसार गतिशील आवंटन का उपयोग करना होगा:
class Dummy
{
const byte* buffer;
public:
Dummy(int size):buffer(new byte[size])
{
}
~Dummy()
{
delete [] bufer;
}
};
इस मामले में, हमारे पास पहले नमूने की तुलना में अधिक विकल्प हैं (उदाहरण के लिए प्रत्येक के लिए Dummy
अलग-अलग buffer
आकार के साथ विभिन्न वस्तुओं का उपयोग करें ), लेकिन हमारे पास विखंडन के मुद्दे हो सकते हैं।
एक विध्वंसक के उपयोग पर ध्यान दें, यह सुनिश्चित करने के लिए buffer
कि कोई Dummy
आवृत्ति हटाए जाने पर स्मृति को आवंटित किया जाएगा ।
मैंने malloc()
avr-libc द्वारा उपयोग किए जाने वाले एल्गोरिथ्म पर एक नज़र डाली है, और कुछ उपयोग पैटर्न प्रतीत होते हैं जो ढेर विखंडन के दृष्टिकोण से सुरक्षित हैं:
इसके द्वारा मेरा मतलब है: कार्यक्रम की शुरुआत में आपको सभी की आवश्यकता है, और इसे कभी भी मुक्त न करें। बेशक, इस मामले में, आप स्थैतिक बफर का उपयोग कर सकते हैं ...
अर्थ: आप कुछ और आवंटित करने से पहले बफर को मुक्त करते हैं। एक उचित उदाहरण इस तरह लग सकता है:
void foo()
{
size_t size = figure_out_needs();
char * buffer = malloc(size);
if (!buffer) fail();
do_whatever_with(buffer);
free(buffer);
}
यदि अंदर कोई मॉलॉक नहीं है do_whatever_with()
, या यदि यह फ़ंक्शन जो कुछ भी आवंटित करता है उसे मुक्त करता है, तो आप विखंडन से सुरक्षित हैं।
यह पिछले दो मामलों का सामान्यीकरण है। यदि आप ढेर का उपयोग एक स्टैक की तरह करते हैं (अंतिम बार पहले बाहर होता है), तो यह एक स्टैक की तरह व्यवहार करेगा न कि टुकड़ा। यह ध्यान दिया जाना चाहिए कि इस मामले में अंतिम आवंटित बफर का आकार बदलना सुरक्षित है realloc()
।
यह विखंडन को रोक नहीं पाएगा, लेकिन यह इस अर्थ में सुरक्षित है कि ढेर अधिकतम उपयोग किए गए आकार से बड़ा नहीं होगा । यदि आपके सभी बफ़र्स का आकार समान है, तो आप यह सुनिश्चित कर सकते हैं कि, जब भी आप उनमें से किसी एक को मुक्त करेंगे, स्लॉट बाद के आवंटन के लिए उपलब्ध होगा।
डायनेमिक एलोकेशन का उपयोग करना (जैसे malloc
/ free
या new
/ delete
) स्वाभाविक रूप से खराब नहीं है। वास्तव में, स्ट्रिंग प्रोसेसिंग (जैसे String
ऑब्जेक्ट के माध्यम से ) जैसी किसी चीज़ के लिए, यह अक्सर काफी मददगार होता है। ऐसा इसलिए है क्योंकि कई स्केच में स्ट्रिंग्स के कई छोटे टुकड़े का उपयोग किया जाता है, जो अंततः एक बड़े में संयुक्त हो जाता है। डायनेमिक एलोकेशन का उपयोग करने से आप केवल उतनी ही मेमोरी का उपयोग कर सकते हैं जितनी आपको प्रत्येक के लिए आवश्यक है। इसके विपरीत, हर एक के लिए एक निश्चित आकार के स्थिर बफर का उपयोग करने से बहुत सी जगह बर्बाद हो सकती है (इससे मेमोरी बहुत तेजी से बाहर निकल सकती है), हालांकि यह पूरी तरह से संदर्भ पर निर्भर करता है।
कहा जा रहा है कि सभी के साथ, यह सुनिश्चित करना बहुत महत्वपूर्ण है कि मेमोरी का उपयोग अनुमानित है। रन-टाइम परिस्थितियों (जैसे इनपुट) के आधार पर मनमानी मात्रा में मेमोरी का उपयोग करने के लिए स्केच को आसानी से या बाद में समस्या का कारण बन सकता है। कुछ मामलों में, यह पूरी तरह से सुरक्षित हो सकता है, उदाहरण के लिए यदि आप जानते हैं कि उपयोग कभी भी बहुत अधिक नहीं होगा। हालांकि प्रोग्रामिंग प्रक्रिया के दौरान स्केच बदल सकते हैं। जब किसी चीज को बाद में बदल दिया जाता है, तो एक धारणा को जल्दी ही भुला दिया जा सकता है, जिससे एक अप्रत्याशित समस्या पैदा हो सकती है।
मजबूती के लिए, आमतौर पर निश्चित आकार के बफ़र्स के साथ काम करना बेहतर होता है जहाँ संभव हो, और शुरू से उन सीमाओं के साथ स्पष्ट रूप से काम करने के लिए स्केच डिज़ाइन करें। इसका मतलब है कि स्केच, या किसी भी अनपेक्षित रन-टाइम परिस्थितियों में कोई भी भविष्य में परिवर्तन, किसी भी स्मृति समस्याओं का कारण नहीं होना चाहिए।
मैं उन लोगों से असहमत हूं जो सोचते हैं कि आपको इसका उपयोग नहीं करना चाहिए या यह आम तौर पर अनावश्यक है। मेरा मानना है कि यह खतरनाक हो सकता है यदि आप भारतीय नौसेना पोत और इसके बारे में नहीं जानते हैं, लेकिन यह उपयोगी है। मेरे पास ऐसे मामले हैं जो मुझे नहीं पता (और पता करने की परवाह नहीं करनी चाहिए) एक संरचना या एक बफर का आकार (संकलन समय या रन समय पर), खासकर जब यह पुस्तकालयों की बात आती है तो मैं दुनिया में भेज देता हूं। मैं मानता हूं कि यदि आप एप्लिकेशन केवल एकल, ज्ञात संरचना के साथ काम कर रहे हैं, तो आपको संकलन समय पर उस आकार में सेंकना चाहिए।
उदाहरण: मेरे पास एक सीरियल पैकेट क्लास (एक पुस्तकालय) है जो मनमाने ढंग से लंबाई के डेटा पेलोड ले सकता है (संरचना, uint16_t की सरणी, आदि) हो सकता है। उस कक्षा के भेजने के अंत में आप बस Packet.send () विधि को उस चीज़ का पता बताएं जिसे आप भेजना चाहते हैं और हार्डवेयरशेरियल पोर्ट जिसके माध्यम से आप इसे भेजना चाहते हैं। हालाँकि, प्राप्त होने के अंत में, मुझे उस आवक पेलोड को धारण करने के लिए एक गतिशील रूप से आवंटित बफर की आवश्यकता होती है, क्योंकि पेलोड किसी भी समय एक अलग संरचना हो सकता है, उदाहरण के लिए, एप्लिकेशन की स्थिति पर निर्भर करता है। अगर मैं केवल एक संरचना को आगे और पीछे भेज रहा हूं, तो मैं केवल उस बफर को आकार दूंगा, जिसे संकलन समय पर होना चाहिए। लेकिन, उस मामले में जहां पैकेट समय के साथ अलग-अलग लंबाई के हो सकते हैं, मॉलॉक () और फ्री () इतने बुरे नहीं हैं।
मैंने दिनों के लिए निम्नलिखित कोड के साथ परीक्षण चलाए हैं, यह लगातार लूप देता है, और मुझे स्मृति विखंडन का कोई सबूत नहीं मिला है। गतिशील रूप से आवंटित स्मृति को मुक्त करने के बाद, मुक्त राशि अपने पिछले मूल्य पर लौट आती है।
// found at learn.adafruit.com/memories-of-an-arduino/measuring-free-memory
int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
uint8_t *_tester;
while(1) {
uint8_t len = random(1, 1000);
Serial.println("-------------------------------------");
Serial.println("len is " + String(len, DEC));
Serial.println("RAM: " + String(freeRam(), DEC));
Serial.println("_tester = " + String((uint16_t)_tester, DEC));
Serial.println("alloating _tester memory");
_tester = (uint8_t *)malloc(len);
Serial.println("RAM: " + String(freeRam(), DEC));
Serial.println("_tester = " + String((uint16_t)_tester, DEC));
Serial.println("Filling _tester");
for (uint8_t i = 0; i < len; i++) {
_tester[i] = 255;
}
Serial.println("RAM: " + String(freeRam(), DEC));
Serial.println("freeing _tester memory");
free(_tester); _tester = NULL;
Serial.println("RAM: " + String(freeRam(), DEC));
Serial.println("_tester = " + String((uint16_t)_tester, DEC));
delay(1000); // quick look
}
मैंने रैम में या इस पद्धति का उपयोग करके इसे गतिशील रूप से आवंटित करने की मेरी क्षमता में किसी भी प्रकार की गिरावट नहीं देखी है, इसलिए मैं कहूंगा कि यह एक व्यवहार्य उपकरण है। FWIW।
क्या Arduino के साथ Malloc () और free () का उपयोग करना वास्तव में बुरा विचार है?
छोटा जवाब हां है। नीचे कारण हैं:
यह सब समझने के बारे में है कि एक एमपीयू क्या है और उपलब्ध संसाधनों की कमी के भीतर कैसे प्रोग्राम किया जाए। Arduino Uno 32KB ISP फ्लैश मेमोरी, 1024B EEPROM और 2KB SRAM के साथ ATmega328p MPU का उपयोग करता है । यह स्मृति संसाधनों का एक बहुत कुछ नहीं है।
याद रखें कि 2KB SRAM का उपयोग सभी वैश्विक चर, स्ट्रिंग शाब्दिक, ढेर और ढेर के संभावित उपयोग के लिए किया जाता है। स्टैक को ISR के लिए हेड रूम भी होना चाहिए।
स्मृति लेआउट है:
टोड पीसी / लैपटॉप में मेमोरी की मात्रा 1.000.000 गुना से अधिक होती है। एक 1 Mbyte डिफ़ॉल्ट स्टैक स्पेस प्रति थ्रेड असामान्य नहीं है, लेकिन एक MPU पर पूरी तरह से अवास्तविक है।
एक एम्बेडेड सॉफ़्टवेयर प्रोजेक्ट के लिए एक संसाधन बजट करना पड़ता है। यह आईएसआर विलंबता, आवश्यक मेमोरी स्पेस, गणना शक्ति, निर्देश चक्र, आदि का आकलन कर रहा है। दुर्भाग्य से कोई भी मुफ्त-लंच नहीं है और हार्ड-टाइम एम्बेडेड प्रोग्रामिंग मास्टर करने के लिए प्रोग्रामिंग कौशल का सबसे कठिन है।
ठीक है, मुझे पता है कि यह एक पुराना सवाल है, लेकिन जितना अधिक मैं उत्तरों के माध्यम से पढ़ता हूं उतना ही मैं एक अवलोकन पर वापस आता रहता हूं जो नमकीन लगता है।
लगता है कि ट्यूरिंग हाल्टिंग समस्या के साथ एक लिंक यहाँ है। गतिशील आवंटन के कारण उक्त 'पड़ाव' की संभावना बढ़ जाती है इसलिए प्रश्न जोखिम-सहिष्णुता में से एक बन जाता है। हालांकि malloc()
असफल होने की संभावना को दूर करने के लिए सुविधाजनक है और आगे भी, यह अभी भी एक वैध परिणाम है। ओपी पूछता है कि प्रश्न केवल तकनीक के बारे में प्रतीत होता है, और हां उपयोग किए गए पुस्तकालयों या विशिष्ट एमपीयू के विवरण मायने रखते हैं; वार्तालाप कार्यक्रम के रुकने या किसी अन्य असामान्य अंत के जोखिम को कम करने की ओर मुड़ता है। हमें पर्यावरण के अस्तित्व को पहचानने की आवश्यकता है जो जोखिम को अलग तरह से सहन करते हैं। एक एलईडी-पट्टी पर सुंदर रंगों को प्रदर्शित करने के लिए मेरा शौक परियोजना किसी को मार नहीं देगी यदि कुछ असामान्य होता है लेकिन दिल-फेफड़े की मशीन के अंदर एमसीयू होने की संभावना होगी।
मेरी एलईडी-पट्टी के लिए, मुझे परवाह नहीं है अगर यह लॉक हो जाता है, तो मैं इसे रीसेट कर दूंगा। अगर मैं एक हार्ट-लंग मशीन एक MCU यह के परिणामों अप ताला लगा या संचालित करने में नाकाम रहने के द्वारा नियंत्रित पर थे सचमुच जीवन और मौत, इसलिए सवाल कर रहे हैं के बारे में malloc()
और free()
श्री प्रदर्शन की संभावना के साथ कैसे इरादा कार्यक्रम सौदों के बीच विभाजित किया जाना चाहिए ट्यूरिंग की प्रसिद्ध समस्या। यह भूलना आसान हो सकता है कि यह एक गणितीय प्रमाण है और खुद को यह समझाने के लिए कि यदि हम केवल पर्याप्त चतुर हैं तो हम गणना की सीमाओं के हताहत होने से बच सकते हैं।
इस प्रश्न के दो स्वीकृत उत्तर होने चाहिए, एक उन लोगों के लिए जो द हेलिंग प्रॉब्लम को फेस करते समय पलक झपकने के लिए मजबूर हो जाते हैं, और अन्य सभी के लिए। हालांकि आर्डिनो के अधिकांश उपयोग मिशन महत्वपूर्ण या जीवन-और-मृत्यु अनुप्रयोगों की संभावना नहीं है, फिर भी भेद अभी भी है चाहे एमपीयू आप कोडिंग हो सकते हैं।
नहीं, लेकिन उन्हें मुफ्त में () आवंटित स्मृति के संबंध में बहुत सावधानी से इस्तेमाल किया जाना चाहिए। मुझे कभी समझ नहीं आया कि लोग क्यों कहते हैं कि डायरेक्ट मेमोरी मैनेजमेंट से बचना चाहिए क्योंकि यह असंगतता का एक स्तर है जो आम तौर पर सॉफ्टवेयर विकास के साथ असंगत है।
ड्रोन को नियंत्रित करने के लिए अपने arduino का उपयोग करके अपने कहने दें। आपके कोड के किसी भी हिस्से में कोई भी त्रुटि संभावित रूप से आकाश से बाहर गिर सकती है और किसी या किसी को चोट पहुंचा सकती है। दूसरे शब्दों में, अगर किसी में मॉलॉक का उपयोग करने की क्षमता का अभाव है, तो उन्हें संभवतः बिल्कुल भी कोडिंग नहीं करनी चाहिए क्योंकि बहुत सारे अन्य क्षेत्र हैं जहां छोटे कीड़े गंभीर मुद्दों का कारण बन सकते हैं।
क्या मॉलॉक के कारण कीड़े नीचे ट्रैक करने और ठीक करने के लिए कठिन हैं? हाँ, लेकिन यह जोखिम के बजाय कोडर्स भाग पर निराशा की बात है। जहां तक जोखिम जाता है, आपके कोड का कोई भी हिस्सा मॉलोक की तुलना में समान या अधिक जोखिम भरा हो सकता है यदि आप यह सुनिश्चित करने के लिए कदम नहीं उठाते हैं कि यह सही है।