จะเกิดอะไรขึ้นเมื่อไมโครคอนโทรลเลอร์หมด RAM


12

อาจเป็นเรื่องบังเอิญ แต่ฉันสังเกตเห็นว่าไมโครคอนโทรลเลอร์ใช้การรีบูตเมื่อ RAM หมด (Atmega 328 ถ้าฮาร์ดแวร์เฉพาะ) นั่นคือสิ่งที่ไมโครคอนโทรลเลอร์ทำเมื่อหน่วยความจำไม่เพียงพอ? ถ้าไม่เกิดอะไรขึ้น

ทำไม / อย่างไร ตัวชี้สแต็กจะเพิ่มขึ้นอย่างแน่นอนในช่วงหน่วยความจำที่ไม่ได้จัดสรร (หรือย้อนกลับ) แต่เกิดอะไรขึ้นแล้ว: มีการป้องกันบางอย่างที่ทำให้มันรีบูทหรือเป็นผลมาจากการเขียนทับวิกฤต ข้อมูล (ซึ่งฉันคิดว่าแตกต่างจากรหัสที่ฉันคิดว่าเรียกใช้โดยตรงจากแฟลช)

ฉันไม่แน่ใจว่าสิ่งนี้ควรอยู่ที่นี่หรือบน Stack Overflow โปรดแจ้งให้เราทราบว่าควรย้ายสิ่งนี้หรือไม่แม้ว่าฉันค่อนข้างแน่ใจว่าฮาร์ดแวร์มีบทบาทในเรื่องนั้น

ปรับปรุง

ฉันควรชี้ให้เห็นว่าฉันสนใจกลไกที่แท้จริงที่อยู่เบื้องหลังความเสียหายของหน่วยความจำ (มันเป็นผลมาจากการที่ SP พลิก -> นั้นขึ้นอยู่กับการจับคู่หน่วยความจำของ uC เป็นต้น) หรือไม่?


8
micros บางตัวจะรีเซ็ตหากคุณพยายามเข้าถึงที่อยู่ที่ไม่ถูกต้อง มันเป็นคุณสมบัติที่มีคุณค่านำมาใช้ในฮาร์ดแวร์ บางครั้งมันอาจกระโดดลงไปที่ใดก็ได้โดยพลการ (พูดว่าคุณปิดกั้นที่อยู่ผู้ส่งคืนสำหรับ ISR) บางทีอาจใช้ข้อมูลแทนรหัสหากสถาปัตยกรรมอนุญาต ของ.
Spehro Pefhany

2
โปรเซสเซอร์ไม่สามารถเรียกใช้ RAM หมดไม่มีคำสั่งที่จะทำให้ RAM หมด RAM หมดเป็นแนวคิดซอฟต์แวร์ทั้งหมด
user253751

คำตอบ:


14

โดยทั่วไปแล้วสแต็คและฮีปจะชนกัน เมื่อถึงจุดนั้นมันก็ยุ่งเหยิงไปหมด

ขึ้นอยู่กับ MCU หนึ่งในหลาย ๆ สิ่งที่อาจเกิดขึ้น (หรือจะ)

  1. ตัวแปรเสียหาย
  2. สแต็กได้รับความเสียหาย
  3. โปรแกรมได้รับความเสียหาย

เมื่อ 1 เกิดขึ้นคุณจะเริ่มมีพฤติกรรมแปลก ๆ - สิ่งที่ไม่ควรทำในสิ่งที่ควรทำ เมื่อ 2 เกิดขึ้นนรกทุกรูปแบบจะหลวม หากที่อยู่ผู้ส่งคืนบนสแต็ก (ถ้ามี) จะเกิดความเสียหายตำแหน่งที่การโทรปัจจุบันจะกลับไปเป็นการเดาของทุกคน ในเวลานั้นโดยทั่วไปแล้ว MCU จะเริ่มทำสิ่งสุ่ม เมื่อ 3 เกิดขึ้นอีกครั้งใครจะรู้ว่าจะเกิดอะไรขึ้น สิ่งนี้จะเกิดขึ้นเมื่อคุณเรียกใช้โค้ดจาก RAM เท่านั้น

โดยทั่วไปเมื่อสแต็กเกิดความเสียหายมันจะจบลง เกิดอะไรขึ้นกับ MCU

อาจเป็นได้ว่าการพยายามจัดสรรหน่วยความจำในครั้งแรกล้มเหลวดังนั้นความเสียหายจะไม่เกิดขึ้น ในกรณีนี้ MCU อาจเพิ่มข้อยกเว้น หากไม่มีการติดตั้งตัวจัดการข้อยกเว้นบ่อยครั้งที่ MCU จะหยุดชะงัก (เทียบเท่าwhile (1);หากมีการติดตั้งตัวจัดการแล้วมันอาจรีบูตใหม่หมดจด

หากการจัดสรรหน่วยความจำดำเนินต่อไปหรือหากพยายามล้มเหลวและเพิ่งดำเนินการต่อโดยไม่มีการจัดสรรหน่วยความจำคุณจะเข้าสู่อาณาจักรของ "ใครจะรู้" MCU อาจสิ้นสุดการรีบูตตัวเองผ่านการรวมเหตุการณ์ที่ถูกต้อง (การขัดจังหวะทำให้การรีเซ็ตชิป ฯลฯ ) แต่ไม่มีการรับประกันว่าจะเกิดอะไรขึ้น

สิ่งที่มักจะมีโอกาสเกิดขึ้นได้สูงคือถ้าเปิดใช้งานแล้วจะเป็นตัวจับเวลาจ้องจับผิดภายใน (หากมีอยู่) หมดเวลาและรีบูตชิป เมื่อโปรแกรมไปถึง AWOL โดยสมบูรณ์จากความผิดพลาดประเภทนี้คำแนะนำในการรีเซ็ตตัวจับเวลาโดยทั่วไปจะไม่ทำงานดังนั้นจึงจะหมดเวลาและรีเซ็ต


ขอบคุณสำหรับคำตอบของคุณมันเป็นบทสรุปที่ยอดเยี่ยมของเอฟเฟกต์ บางทีฉันควรระบุว่าฉันต้องการรายละเอียดเพิ่มเติมเกี่ยวกับกลไกที่แท้จริงของความเสียหายเหล่านั้น: RAM ทั้งหมดถูกจัดสรรให้กับสแต็กและฮีปดังนั้นตัวชี้สแต็กจะหมุนทับและเขียนทับตัวแปร / ที่อยู่ก่อนหน้าหรือไม่ หรือน้อยกว่านั้นขึ้นอยู่กับการทำแผนที่หน่วยความจำของแต่ละไมโคร อีกทางเลือกหนึ่ง (อาจเป็นหัวข้อในตัวเอง) ฉันสนใจที่จะเรียนรู้วิธีการใช้งานตัวจัดการฮาร์ดแวร์เหล่านั้น
นายMystère

1
ส่วนใหญ่จะขึ้นอยู่กับคอมไพเลอร์และไลบรารี C มาตรฐานที่ใช้งานอยู่ บางครั้งก็ขึ้นอยู่กับวิธีการกำหนดค่าคอมไพเลอร์ (สคริปต์ตัวเชื่อมโยง ฯลฯ )
Majenko

คุณสามารถขยายความในนั้นได้ด้วยตัวอย่างสักสองสามข้อ?
นายMystère

ไม่จริงไม่ ระบบบางระบบจัดสรรพื้นที่ จำกัด สำหรับเซ็กเมนต์ต่าง ๆ บางระบบไม่ บางคนใช้ linker สคริปต์เพื่อกำหนดกลุ่ม แต่บางคนก็ไม่ทำ เลือกไมโครคอนโทรลเลอร์ที่เป็นที่สนใจของคุณและทำการวิจัยเกี่ยวกับวิธีการจัดสรรหน่วยความจำของมัน
Majenko

12

มุมมองทางเลือก: ไมโครคอนโทรลเลอร์ไม่หน่วยความจำไม่เพียงพอ

อย่างน้อยไม่ใช่เมื่อตั้งโปรแกรมอย่างเหมาะสม การเขียนโปรแกรมไมโครคอนโทรลเลอร์ไม่เหมือนกับการเขียนโปรแกรมวัตถุประสงค์ทั่วไปเพื่อทำอย่างถูกต้องคุณจะต้องตระหนักถึงข้อ จำกัด และโปรแกรมของมัน มีเครื่องมือที่ช่วยให้มั่นใจได้ ค้นหาพวกเขาและเรียนรู้พวกเขา - อย่างน้อยวิธีการอ่านสคริปต์ linker และคำเตือน

อย่างไรก็ตามอย่างที่ Majenko และคนอื่น ๆ บอกว่าไมโครคอนโทรลเลอร์ที่ตั้งโปรแกรมไม่ดีอาจหมดหน่วยความจำแล้วทำทุกอย่างรวมถึง infinite loop (อย่างน้อยก็ให้โอกาสตัวนับจ้องจับผิดในการรีเซ็ตมัน )

กฎการโปรแกรมทั่วไปสำหรับไมโครคอนโทรลเลอร์หลีกเลี่ยงสิ่งนี้: ตัวอย่างเช่นหน่วยความจำทั้งหมดจะถูกจัดสรรบนสแต็กหรือจัดสรร (แบบโกลบอล) แบบสแตติก ห้ามใช้ "ใหม่" หรือ "malloc" ดังนั้นการเรียกซ้ำเพื่อให้ความลึกสูงสุดของการซ้อนรูทีนย่อยสามารถวิเคราะห์และแสดงให้พอดีกับสแต็กที่มีอยู่

ดังนั้นที่เก็บข้อมูลสูงสุดที่ต้องการสามารถคำนวณได้เมื่อโปรแกรมรวบรวมหรือเชื่อมโยงและเปรียบเทียบกับขนาดหน่วยความจำ (มักเข้ารหัสในสคริปต์ตัวเชื่อมโยง) สำหรับตัวประมวลผลเฉพาะที่คุณกำหนดเป้าหมาย

ไมโครคอนโทรลเลอร์อาจไม่ได้ใช้หน่วยความจำไม่เพียงพอ แต่โปรแกรมของคุณอาจ และในกรณีนั้นคุณจะได้

  • เขียนใหม่เล็กลงหรือ
  • เลือกโปรเซสเซอร์ที่ใหญ่กว่า (มักใช้กับขนาดหน่วยความจำที่แตกต่างกัน)

กฎทั่วไปหนึ่งข้อสำหรับการเขียนโปรแกรมไมโครคอนโทรลเลอร์คือMISRA-Cซึ่งเป็นที่ยอมรับในอุตสาหกรรมยานยนต์

แนวปฏิบัติที่ดีที่สุดในมุมมองของฉันคือการใช้ชุดย่อยSPARK-2014ของ Ada Ada ตั้งเป้าไปที่คอนโทรลเลอร์ขนาดเล็กเช่น AVR, MSP430 และ ARM Cortex อย่างดีพอสมควรและโดยปกติจะให้แบบจำลองที่ดีกว่าสำหรับการเขียนโปรแกรมไมโครคอนโทรลเลอร์กว่า C แต่ SPARK เพิ่มคำอธิบายประกอบให้กับโปรแกรมในรูปแบบของความคิดเห็นซึ่งอธิบายว่าโปรแกรมกำลังทำอะไร

ตอนนี้เครื่องมือ SPARK จะวิเคราะห์โปรแกรมรวมถึงคำอธิบายประกอบเหล่านั้นและพิสูจน์คุณสมบัติของมัน (หรือรายงานข้อผิดพลาดที่อาจเกิดขึ้น) คุณไม่ต้องเสียเวลาหรือพื้นที่โค้ดในการเข้าถึงหน่วยความจำที่ผิดพลาดหรือจำนวนเต็มมากเกินไปเพราะมันได้รับการพิสูจน์แล้วว่าไม่เคยเกิดขึ้น

แม้ว่าจะมีงานที่เกี่ยวข้องกับ SPARK มากขึ้น แต่ประสบการณ์แสดงให้เห็นว่าสามารถรับผลิตภัณฑ์ได้เร็วขึ้นและราคาถูกลงเพราะคุณไม่ได้ใช้เวลาไล่ตามการรีบูตลึกลับและพฤติกรรมแปลก ๆ

การเปรียบเทียบ MISRA-C และ SPARK


3
+1 สิ่งนี้ การย้ายmalloc()(และเป็นเพื่อนร่วม C ++ new) ไปยัง AVR เป็นหนึ่งในสิ่งที่เลวร้ายที่สุดที่คนอาร์ดิโนสามารถทำได้และนำไปสู่โปรแกรมเมอร์ที่สับสนมาก ๆ หลายคนที่มีรหัสที่แตกหักทั้งในฟอรัมและแลกเปลี่ยนอาร์ดิโน มีสถานการณ์น้อยมากที่การmallocใช้ ATmega นั้นมีประโยชน์
Connor Wolf

3
+1 สำหรับปรัชญา -1 สำหรับสมจริง หากสิ่งใดถูกตั้งโปรแกรมอย่างเหมาะสมก็ไม่จำเป็นต้องมีคำถามนี้ คำถามคือสิ่งที่เกิดขึ้นเมื่อไมโครคอนโทรลเลอร์ควบคุมหน่วยความจำไม่เพียงพอ วิธีการป้องกันไม่ให้หน่วยความจำไม่เพียงพอเป็นอีกคำถามหนึ่ง ในบันทึกอื่นการเรียกซ้ำเป็นเครื่องมือที่ทรงพลังทั้งในการแก้ปัญหาและการใช้งานสแต็กหมด
PkP

2
@Brian เนื่องจากฉันไม่ใช่คนโง่ฉันเห็นด้วยอย่างชัดเจนกับคุณ ฉันแค่คิดถึงเรื่องนี้ในมุมมองแบบย้อนกลับ - ฉันชอบที่จะหวังว่าเมื่อคุณตระหนักถึงผลกระทบที่น่ากลัวจากการใช้หน่วยความจำไม่เพียงพอ (สแต็ค) คุณจะต้องหาวิธีในการป้องกันไม่ให้เกิดขึ้น วิธีนี้ทำให้คุณมีแรงผลักดันที่แท้จริงในการค้นหาวิธีปฏิบัติในการเขียนโปรแกรมที่ดีแทนที่จะทำตามคำแนะนำในการเขียนโปรแกรมที่ดี ... และเมื่อคุณเข้าสู่สิ่งกีดขวางหน่วยความจำคุณจะมีแนวโน้มที่จะบังคับใช้แนวทางปฏิบัติที่ดียิ่งขึ้น มันเป็นเพียงจุดชมวิว ...
PkP

2
@PkP: ได้ยินยาดังและชัดเจน ฉันระบุว่านี่เป็นมุมมองทางเลือก - เพราะจริง ๆ แล้วมันไม่ได้ตอบคำถาม!
Brian Drummond

2
@ MisterMystère: โดยทั่วไปแล้วไมโครคอนโทรลเลอร์ไม่ได้มีหน่วยความจำไม่เพียงพอ ไมโครคอนโทรลเลอร์ที่มี RAM 4096 ไบต์เมื่อเปิดเครื่องครั้งแรกจะมี 4096 ไบต์ตลอดไป อาจเป็นไปได้ว่ารหัสอาจพยายามเข้าถึงที่อยู่ที่ไม่มีอยู่หรือคาดว่าวิธีการคำนวณที่อยู่สองวิธีที่แตกต่างกันจะเข้าถึงหน่วยความจำที่ต่างกันเมื่อไม่มี แต่ตัวควบคุมจะดำเนินการตามคำแนะนำที่ให้ไว้
supercat

6

ฉันชอบคำตอบของ Majenko และ +1 ด้วยตัวเอง แต่ฉันต้องการชี้แจงเรื่องนี้ให้ชัดเจน:

สิ่งใด สามารถเกิดขึ้นได้เมื่อไมโครคอนโทรลเลอร์หมดหน่วยความจำ

คุณไม่สามารถพึ่งพาอะไรได้เลยเมื่อมันเกิดขึ้น เมื่อเครื่องไม่มีหน่วยความจำสแต็คสแต็กส่วนใหญ่อาจเสียหาย และเป็นสิ่งที่เกิดขึ้นอะไรก็ได้ที่สามารถเกิดขึ้นได้ ค่าตัวแปรการรั่วไหลการลงทะเบียนชั่วคราวทั้งหมดเกิดความเสียหายขัดขวางการไหลของโปรแกรม ถ้า / / / elses สามารถประเมินได้ไม่ถูกต้อง ที่อยู่ผู้ส่งถูกอ่านไม่ออกทำให้โปรแกรมข้ามไปยังที่อยู่แบบสุ่ม รหัสใด ๆ ที่คุณเขียนในโปรแกรมอาจทำงานได้ (พิจารณารหัสเช่น: "ถ้า [เงื่อนไข] ดังนั้น {fire_all_missiles ();}") นอกจากนี้ยังมีคำแนะนำทั้งหมดที่คุณยังไม่ได้เขียนสามารถเรียกใช้งานได้เมื่อคอร์กระโดดไปยังตำแหน่งหน่วยความจำที่ไม่ได้เชื่อมต่อ การเดิมพันทั้งหมดจะปิด


2
ขอบคุณสำหรับภาคผนวกฉันชอบสาย fire_all_missiles () เป็นพิเศษ
นายMystère

1

AVR ได้รีเซ็ตเวกเตอร์ที่แอดเดรสศูนย์ เมื่อคุณเขียนทับกองซ้อนด้วยถังขยะแบบสุ่มคุณจะวนไปวนมารอบ ๆ และเขียนทับที่อยู่ผู้ส่งคืนบางส่วนและจะชี้ไปที่ "ไม่มีที่ไหนเลย" จากนั้นเมื่อคุณกลับจากรูทีนย่อยไปที่นั้นการดำเนินการจะวนรอบไปยังที่อยู่ 0 โดยปกติแล้วการข้ามไปยังตัวจัดการการรีเซ็ต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.