Apa yang terjadi ketika mikrokontroler kehabisan RAM?

12

Ini mungkin hanya kebetulan tapi saya perhatikan mikrokontroler yang saya gunakan reboot ketika mereka kehabisan RAM (Atmega 328 jika hardware khusus). Itukah yang dilakukan mikrokontroler ketika kehabisan memori? Jika tidak, lalu apa yang terjadi?

Mengapa bagaimana? Penunjuk tumpukan tentu saja ditingkatkan secara membuta ke rentang memori yang tidak dialokasikan (atau terguling), tetapi yang terjadi kemudian: apakah ada beberapa jenis perlindungan yang membuatnya reboot atau apakah itu (di antara efek lainnya) hasil dari penimpaan kritis data (yang saya anggap berbeda dari kode yang saya pikir dijalankan langsung dari flash)?

Saya tidak yakin ini harus ada di sini atau di Stack Overflow, tolong beri tahu saya jika ini harus dipindahkan walaupun saya cukup yakin perangkat keras memiliki peran dalam hal itu.

Memperbarui

Saya harus menunjukkan bahwa saya sangat tertarik dengan mekanisme aktual di balik kerusakan memori (apakah ini hasil dari penggulingan SP -> apakah itu tergantung pada pemetaan memori UC, dll.)?

Tuan Mystère
sumber
8
Beberapa micros akan direset jika Anda mencoba mengakses alamat yang tidak valid. Ini adalah fitur berharga yang diimplementasikan dalam perangkat keras. Di lain waktu itu mungkin berakhir dengan melompat ke suatu tempat yang sewenang-wenang (misalnya Anda telah menghancurkan alamat pengirim untuk ISR), mungkin mengeksekusi data daripada kode jika arsitektur mengizinkannya, dan mungkin terjebak dalam lingkaran yang dibawa oleh pengawas membawa keluar dari.
Spehro Pefhany
2
Prosesor tidak dapat kehabisan RAM, tidak ada instruksi yang akan membuatnya kehabisan RAM. Kehabisan RAM sepenuhnya merupakan konsep perangkat lunak.
user253751

Jawaban:

14

Secara umum tumpukan dan tumpukan menabrak satu sama lain. Pada saat itu semuanya menjadi berantakan.

Tergantung pada MCU, satu dari beberapa hal dapat (atau akan) terjadi.

  1. Variabel rusak
  2. Tumpukan rusak
  3. Program rusak

Ketika saya terjadi Anda mulai mendapatkan perilaku aneh - hal-hal tidak melakukan apa yang seharusnya. Ketika 2 terjadi, semua jenis neraka lepas. Jika alamat pengirim di tumpukan (jika ada) rusak, maka panggilan saat ini akan kembali adalah dugaan siapa pun. Pada saat itu pada dasarnya MCU akan mulai melakukan hal-hal acak. Ketika 3 terjadi lagi, siapa yang tahu persis apa yang akan terjadi. Ini hanya terjadi ketika Anda mengeksekusi kode dari RAM.

Secara umum, ketika tumpukan rusak, semua sudah berakhir. Yang terjadi adalah ke MCU.

Mungkin mencoba mengalokasikan memori pada awalnya gagal sehingga korupsi tidak terjadi. Dalam hal ini MCU dapat mengajukan pengecualian. Jika tidak ada pengecualian handler yang diinstal, maka MCU yang paling sering hanya akan berhenti (setara dengan while (1);. Jika ada handler yang diinstal, maka mungkin reboot secara bersih.

Jika alokasi memori tidak berjalan, atau jika mencoba, gagal, dan hanya berlanjut tanpa memori yang dialokasikan, maka Anda masuk ke ranah "siapa yang tahu?". MCU mungkin akan me-reboot dirinya sendiri melalui kombinasi peristiwa yang tepat (interupsi yang menyebabkannya mengatur ulang chip, dll), tetapi tidak ada jaminan hal itu terjadi.

Apa yang biasanya bisa menjadi probabilitas tinggi terjadi, meskipun, jika diaktifkan, adalah pengawas waktu internal (jika ada) waktu keluar dan me-reboot chip. Ketika program berjalan sepenuhnya AWOL melalui jenis crash ini petunjuk untuk mengatur ulang timer umumnya tidak akan berjalan, sehingga akan habis dan reset.

Majenko
sumber
Terima kasih atas jawaban Anda, ini ringkasan efek yang luar biasa. Mungkin saya seharusnya telah menetapkan bahwa saya ingin lebih detail tentang mekanisme aktual dari korupsi tersebut: apakah seluruh RAM dialokasikan untuk ditumpuk dan ditumpuk, sehingga penunjuk tumpukan berguling dan menimpa variabel / alamat sebelumnya? Atau apakah itu kurang tergantung pada pemetaan memori masing-masing mikro? Secara opsional (mungkin ini adalah topiknya sendiri), saya akan tertarik mempelajari bagaimana penangan perangkat keras tersebut diimplementasikan.
Tuan Mystère
1
Ini sebagian besar tergantung pada kompiler dan pustaka C standar yang digunakan. Terkadang juga tergantung pada bagaimana kompiler dikonfigurasikan (skrip tautan, dll.).
Majenko
Bisakah Anda mengembangkannya, mungkin dengan beberapa contoh?
Tuan Mystère
Tidak juga, tidak. Beberapa sistem mengalokasikan ruang yang terbatas untuk segmen yang berbeda, beberapa tidak. Beberapa menggunakan skrip linker untuk mendefinisikan segmen, beberapa tidak. Pilih mikrokontroler yang menarik bagi Anda dan lakukan riset tentang bagaimana alokasi memorinya bekerja.,
Majenko
12

Pandangan alternatif: Mikrokontroler tidak kehabisan memori.

Paling tidak, tidak ketika diprogram dengan benar. Memprogram mikrokontroler tidak persis seperti pemrograman tujuan umum, untuk melakukannya dengan benar, Anda harus mengetahui kendala dan programnya. Ada alat untuk membantu memastikan ini. Cari dan pelajari - setidaknya cara membaca skrip tautan dan peringatan.

Namun seperti yang dikatakan Majenko dan yang lainnya, mikrokontroler yang diprogram dengan buruk dapat kehabisan memori, dan kemudian melakukan apa saja termasuk infinite loop (yang setidaknya memberi pengawas waktu kesempatan untuk mengatur ulang. Anda mengaktifkan pengawas waktu, bukan? )

Aturan pemrograman umum untuk mikrokontroler menghindari ini: misalnya, semua memori dialokasikan pada stack atau dialokasikan secara statis (global); "Baru" atau "malloc" dilarang. Demikian juga rekursi, sehingga kedalaman maksimum dari subrutin bersarang dapat dianalisis dan ditampilkan agar sesuai dengan tumpukan yang tersedia.

Dengan demikian, penyimpanan maksimum yang diperlukan dapat dihitung ketika program dikompilasi atau ditautkan, dan dibandingkan dengan ukuran memori (sering dikodekan dalam skrip tautan) untuk prosesor spesifik yang Anda targetkan.

Maka mikrokontroler mungkin tidak kehabisan memori, tetapi program Anda mungkin. Dan dalam hal ini, Anda harus melakukannya

  • tulis ulang, lebih kecil, atau
  • pilih prosesor yang lebih besar (seringkali tersedia dengan ukuran memori yang berbeda).

Satu set aturan umum untuk pemrograman mikrokontroler adalah MISRA-C , yang diadopsi oleh industri motor.

Praktik terbaik dalam pandangan saya adalah dengan menggunakan subset SPARK-2014 dari Ada. Ada sebenarnya menargetkan pengontrol kecil seperti AVR, MSP430 dan ARM Cortex dengan cukup baik, dan secara inheren menyediakan model yang lebih baik untuk pemrograman mikrokontroler daripada C. Tetapi SPARK menambahkan anotasi ke program, dalam bentuk komentar, yang menggambarkan apa yang sedang dilakukan program.

Sekarang alat SPARK akan menganalisis program, termasuk anotasi tersebut, dan membuktikan properti tentang hal itu (atau melaporkan potensi kesalahan). Anda tidak perlu membuang waktu atau ruang kode yang berhubungan dengan akses memori yang salah atau kelebihan integer karena mereka terbukti tidak pernah terjadi.

Meskipun ada lebih banyak pekerjaan di muka yang terlibat dengan SPARK, pengalaman menunjukkan itu bisa menjadi produk lebih cepat dan lebih murah karena Anda tidak menghabiskan waktu mengejar reboot misterius dan perilaku aneh lainnya.

Perbandingan MISRA-C dan SPARK

Brian Drummond
sumber
3
Beri ini +1. Melakukan porting malloc()(dan ini adalah pendamping C ++ new) ke AVR adalah salah satu hal terburuk yang bisa dilakukan orang Arduino, dan telah menyebabkan banyak, banyak programmer yang sangat bingung dengan kode rusak baik di forum mereka, dan pertukaran stack Arduino. Ada sangat, sangat sedikit situasi di mana memiliki mallocATmega bermanfaat.
Connor Wolf
3
+1 untuk filsafat, -1 untuk realisme. Jika barang diprogram dengan benar, tidak akan ada kebutuhan untuk pertanyaan ini. Pertanyaannya adalah apa yang terjadi ketika mikrokontroler kehabisan memori. Bagaimana mencegah mereka kehabisan memori adalah pertanyaan lain. Pada catatan lain, rekursi adalah alat yang ampuh, baik untuk memecahkan masalah dan kehabisan tumpukan.
PkP
2
@ Brian, karena saya bukan idiot, saya jelas setuju dengan Anda. Saya hanya ingin memikirkannya secara terbalik - saya ingin berharap bahwa ketika Anda menyadari konsekuensi mengerikan dari kehabisan memori (tumpukan), Anda akan mencari cara untuk mencegahnya terjadi. Dengan cara itu Anda memiliki dorongan nyata untuk menemukan praktik pemrograman yang baik alih-alih hanya mengikuti saran pemrograman yang baik ... dan ketika Anda mencapai penghalang memori, Anda lebih cenderung menegakkan praktik yang baik bahkan dengan mengorbankan kenyamanan. Itu hanya sudut pandang ...
PkP
2
@PkP: dengar ya keras dan jelas. Saya memberi label ini sebagai pandangan alternatif - karena itu sebenarnya tidak menjawab pertanyaan!
Brian Drummond
2
@ MisterMystère: Mikrokontroler umumnya tidak kehabisan memori. Sebuah mikrokontroler yang memiliki 4096 byte RAM saat pertama kali dinyalakan akan memiliki 4096 byte selamanya. Mungkin saja kode salah mencoba mengakses alamat yang tidak ada atau berharap bahwa dua metode berbeda alamat komputasi akan mengakses memori yang berbeda ketika mereka tidak, tetapi controller itu sendiri hanya akan menjalankan instruksi yang diberikan.
supercat
6

Saya sangat suka jawaban Majenko dan memberi +1 pada saya sendiri. Tetapi saya ingin mengklarifikasi hal ini ke titik yang tajam:

Apa pun bisa terjadi ketika mikrokontroler kehabisan memori.

Anda benar-benar tidak bisa mengandalkan apa pun ketika itu terjadi. Ketika mesin kehabisan memori tumpukan, tumpukan kemungkinan besar menjadi rusak. Dan ketika itu terjadi, apa pun bisa terjadi. Nilai variabel, tumpahan, register temp, semuanya menjadi rusak, mengganggu aliran program. Jika / maka / elses dapat mengevaluasi secara tidak benar. Alamat pengirim kacau, membuat program melompat ke alamat acak. Kode apa pun yang Anda tulis dalam program dapat dijalankan. (Pertimbangkan kode seperti: "jika [syarat] maka {fire_all_missiles ();}"). Juga sejumlah instruksi yang belum Anda tulis dapat dieksekusi ketika inti melompat ke lokasi memori yang tidak terhubung. Semua taruhan dibatalkan.

PkP
sumber
2
Terima kasih atas tambahannya, saya sangat menyukai baris fire_all_missiles ().
Tuan Mystère
1

AVR memiliki reset vektor di alamat nol. Ketika Anda menimpa tumpukan dengan sampah acak Anda akhirnya akan berputar dan menimpa beberapa alamat pengirim dan itu akan menunjuk ke "tempat"; kemudian ketika Anda kembali dari subrutin ke tempat itu, eksekusi akan berputar ke alamat 0 di mana lompatan untuk mengatur ulang handler biasanya berada.

Ilia
sumber