سؤال

لقد واجهت مشكلة في برنامج C قيد التشغيل على متحكم AVR (ATMEGA328P). أعتقد أنه يرجع إلى تصادم كومة / كومة ولكن أود أن أكون قادرا على تأكيد هذا.

هل هناك أي طريقة يمكنني تصور استخدام SRAM بواسطة المكدس والكومة؟

ملحوظة: يتم تجميع البرنامج مع AVR-GCC ويستخدم AVR LIBC.

تحديث: المشكلة الفعلية التي أحصل عليها هي أن تنفيذ malloc فشل (العودة NULL). الجميع mallocجي يحدث عند بدء التشغيل وجميع freeيحدث جي في نهاية التطبيق (والتي في الممارسة العملية ليست أبدا منذ الجزء الرئيسي من التطبيق في حلقة لا حصر لها). لذلك أنا متأكد من تجزئة ليست هي المشكلة.

هل كانت مفيدة؟

المحلول

أنت تقول Malloc فشل وعودة NULL:

السبب الواضح الذي يجب أن تنظر إليه في البداية هو أن كومة الكومة "كاملة" - أي، أي الذاكرة التي طلبت تخصيص malloc، لأنه غير متوفر.

هناك سيناريوهين لتحمل في الاعتبار:

ج: لديك كومة 16 كيلو، لقد حصلت بالفعل على 10 ك وحاولت و Malloc 10K أخرى. كومة كومة لديك ببساطة صغيرة جدا.

(ب): أكثر شيوعا، لديك كومة من 16 ك كومة، لقد كنت تقوم بمجموعة من مكالمات malloc / free / reallec وكم الكومة الخاصة بك أقل من 50٪ "كاملة": أنت تسمي malloc ل 1 كيلو ويفشل - ما الأمر؟ الإجابة - يتم تجزئة مساحة Heap الحرة - لا يوجد 1K بطابق واحد من الذاكرة الحرة التي يمكن إرجاعها. C مدراء كومة كومة لا يستطيعون ضغط الكومة عند حدوث هذا، لذلك أنت عموما بطريقة سيئة. هناك تقنيات لتجنب التجزأ، ولكن من الصعب معرفة ما إذا كانت هذه هي المشكلة حقا. كنت بحاجة إلى إضافة عمليات تسجيل الحشوات إلى Malloc وحرة حتى تتمكن من الحصول على فكرة عن عمليات الذاكرة الديناميكية التي يتم تنفيذها.

تعديل:

أنت تقول إن جميع malocs تحدث عند بدء التشغيل، لذلك تجزئة ليست هي المشكلة.

في هذه الحالة، يجب أن يكون من السهل استبدال التخصيص الديناميكي مع ثابت.

مثال الرمز القديم:

char *buffer;

void init()
{
  buffer = malloc(BUFFSIZE);
}

رمز جديد:

char buffer[BUFFSIZE];

بمجرد القيام بذلك في كل مكان، يجب أن يحذرك رابطك إذا كان كل شيء لا يمكن أن يصلح إلى الذاكرة المتوفرة. لا تنسى تقليل حجم الكومة - ولكن احذر من أن بعض وظائف نظام التشغيل IO وقت التشغيل قد لا تزال تستخدم كومة الكومة، لذلك قد لا تتمكن من إزالتها بالكامل.

نصائح أخرى

يمكنك التحقق من استخدام RAM ثابت باستخدام avr-size فائدة، كما قللت في
http://www.avrfreaks.net/index.php؟name=pnphpbb2&file=viewtopic&t=62968.,
http://www.avrfreaks.net/index.php؟name=pnphpbb2&file=viewtopic&t=82536.,
http://www.avrfreaks.net/index.php؟name=pnphpbbb2&file=viewtopic&t=95638.,
و http://letsmakerobots.com/node/27115.

avr-size -C -x Filename.elf

(وثائق حجم AVR: http://ccrma.stanford.edu/planetccrma/man/man1/avr-size.1.html. )

يتبع مثالا على كيفية تعيين هذا على IDE: ON رمز :: كتل، مشروع -> خيارات بناء -> خطوات بناء قبل / النشر -> خطوات ما بعد الإنشاء، تشمل:

avr-size -C $(TARGET_OUTPUT_FILE)أو
avr-size -C --mcu=atmega328p $(TARGET_OUTPUT_FILE)

مثال إخراج في نهاية البناء:

AVR Memory Usage
----------------
Device: atmega16

Program:    7376 bytes (45.0% Full)
(.text + .data + .bootloader)

Data:         81 bytes (7.9% Full)
(.data + .bss + .noinit)

EEPROM:       63 bytes (12.3% Full)
(.eeprom) 

البيانات هي استخدام SRAM الخاص بك، وهذا هو فقط المبلغ الذي يعرفه المحول البرمجي في تجميع الوقت. تحتاج أيضا إلى غرفة للأشياء التي تم إنشاؤها في وقت التشغيل (استخدام المكدس بشكل خاص).

للتحقق من استخدام المكدس (RAM ديناميكي)، من http://jeelabs.org/2012/05/22/atmega-memory-use/

فيما يلي وظيفة فائدة صغيرة تحدد مقدار ذاكرة الوصول العشوائي غير المستخدمة حاليا:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

وهنا رسم باستخدام هذا الرمز:

void setup () {
    Serial.begin(57600);
    Serial.println("\n[memCheck]");
    Serial.println(freeRam());
}

تقوم الدالة FreeRam () بإرجاع عدد البايتات بين نهاية الكومة والذاكرة الأخيرة المخصصة على المكدس، لذلك فهي بفعالية كم يمكن أن تنمو المكدس / الكومة قبل تصطدم.

يمكنك التحقق من عودة هذه الوظيفة حول التعليمات البرمجية التي تشك فيها قد تسبب تكدس / كومة الاصطدام.

سيكون النهج المعتاد هو ملء الذاكرة بنمط معروف ثم للتحقق من المناطق التي يتم الكتابة فوقها.

إذا كنت تستخدم كلا من المكدس والكومة، فيمكن أن يكون أكثر صعوبة قليلا. سأشرح ما فعلته عندما لا يتم استخدام كومة كومة. كقاعدة عامة، تجنف جميع الشركات التي عملت بها (في مجال برنامج C Embedded C) باستخدام كومة كومة لمشاريع صغيرة مضمنة - لتجنب عدم اليقين من توفر الذاكرة الكومة. نستخدم المتغيرات المعلنة القانونية بدلا من ذلك.

طريقة واحدة هي ملء معظم منطقة المكدس مع نمط معروف (مثل 0x55) عند بدء التشغيل. عادة ما يتم ذلك بواسطة جزء صغير من التعليمات البرمجية في وقت مبكر من تنفيذ البرامج، إما في بداية الصفحة الرئيسية ()، أو ربما حتى قبل بدء التشغيل ()، في رمز بدء التشغيل. احرص على عدم الكتابة فوق كمية صغيرة من المكدس المستخدمة في هذه النقطة بالطبع. بعد ذلك، بعد تشغيل البرنامج لفترة من الوقت، فحص محتويات مساحة المكدس ومعرفة أين لا يزال 0x55 سليما. كيف تعتمد "تفحص" على الأجهزة المستهدفة. على افتراض أن لديك مصححا متصل، ثم يمكنك ببساطة إيقاف تشغيل Micro وقراءة الذاكرة.

إذا كان لديك مصحح يمكن أن يقوم بإجراء نقطة توقف للوصول إلى الذاكرة (يتوهم أكثر قليلا من نقطة توقف التنفيذ المعتادة)، فيمكنك ضبط نقطة توقف في موقع مكدس معين - مثل الحد الأقصى لمساحتك المكدس. يمكن أن يكون ذلك مفيدا للغاية، لأنه يظهر لك أيضا بالضبط ما يركض الكثير من التعليمات البرمجية عندما يصل إلى حدود استخدام المكدس. ولكنه يتطلب مصححك لدعم ميزة نقطة تبادل الذاكرة وغالبا ما يتم العثور عليها في المصحفين "المنخفض".

إذا كنت تستخدم أيضا كومة، فقد تكون أكثر تعقيدا بعض الشيء لأنه قد يكون من المستحيل التنبؤ عندما تصطدم المكدس والكومة.

لا تستخدم تخصيص كومة / ديناميكي على أهداف مضمنة. خاصة مع معالج مع هذه الموارد المحدودة. بدلا إعادة تصميم طلبك لأن المشكلة ستكرر كما ينمو البرنامج الخاص بك.

على افتراض أنك تستخدم مكدسة واحدة فقط (لذلك ليس RTOS أو أي شيء) وأن المكدس في نهاية الذاكرة، تنمو، في حين أن كومة الكومة تبدأ بعد منطقة BSS / البيانات، تنمو. لقد رأيت تطبيقات MOLOC التي تحقق في الواقع من StackPointer وفشل في تصادم. يمكنك محاولة القيام بذلك.

إذا لم تتمكن من تكييف رمز Malloc، فيمكنك اختيار وضع مكدسك في بداية الذاكرة (باستخدام ملف الرابط). بشكل عام، من الجيد دائما معرفة / تحديد الحد الأقصى لحجم المكدس. إذا وضعته في البداية، فستحصل على خطأ في القراءة بعد بداية ذاكرة الوصول العشوائي. ستكون كومة الكومة في النهاية وربما لا يمكن أن تنمو إلى ما إذا كانت عملية إنهائية لائقة (سيعود NULL بدلا من ذلك). شيء جيد هل تعرف أن لديك حالات خطأ منفصلة لشكلتين منفصلين.

لمعرفة الحد الأقصى لحجم المكدس، يمكنك ملء ذاكرتك بنمط، قم بتشغيل التطبيق ومعرفة مدى ذهبت، انظر أيضا الرد من كريج.

إذا تمكنت من تحرير التعليمات البرمجية لكومة الكومة الخاصة بك، فيمكنك أن تمنعها بضعة بايت إضافية (صعبة على هذه الموارد المنخفضة) على كل كتلة من الذاكرة. هذه البايتات يمكن أن تحتوي على نمط معروف مختلف عن المكدس. قد يوفر لك هذا فكرة إذا كان يعمل مع المكدس من خلال رؤية ذلك، فهو تظهر داخل المكدس أو العكس.

على UNIX مثل أنظمة التشغيل وظيفة مكتبة تدعى SBRK () مع معلمة 0 يسمح لك بالوصول إلى العنوان العلوي لذاكرة الكومة المخصصة بشكل حيوي. قيمة الإرجاع هي مؤشر باطلة * ويمكن مقارنتها بعنوان متغير مخصص للمكدس التعسفي.

باستخدام نتيجة هذه المقارنة يجب استخدامها بعناية. اعتمادا على وحدة المعالجة المركزية والهندسة المعمارية للنظام، قد تنفد المكدس من عنوان مرتفع تعسفي بينما سيترك الكومة المخصصة من الذاكرة المنخفضة المنخفض.

في بعض الأحيان يكون نظام التشغيل يحتوي على مفاهيم أخرى لإدارة الذاكرة (أي OS / 9) الذي يضع كومة وتكدس في قطاعات الذاكرة المختلفة في الذاكرة الحرة. في أنظمة التشغيل هذه - خاصة بالنسبة للأنظمة المضمنة - تحتاج إلى تحديد متطلبات الذاكرة القصوى لتطبيقاتك مقدما لتمكين النظام من تخصيص شرائح الذاكرة من أحجام مطابقة الأحجام.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top