マイクロコントローラーのRAMが不足するとどうなりますか?


12

偶然かもしれませんが、RAM(ハードウェア固有の場合はAtmega 328)を使い果たしたときに、使用したマイクロコントローラーがリブートしたことに気付きました。マイクロコントローラがメモリを使い果たしたとき、それは何をしますか?そうでない場合は、どうなりますか?

なぜ、どのように?スタックポインターは、割り当てられていないメモリ範囲まで盲目的に増加(またはロールオーバー)しますが、その後どうなりますか:リブートする(または他の影響の中でも)重要な上書きの結果である何らかの保護がありますデータ(私はフラッシュから直接実行されると思うコードとは異なると仮定します)?

これがここにあるのかStack Overflowにあるのかわかりません。ハードウェアがその役割を果たしていると確信していますが、これを移動すべきかどうかを教えてください。

更新

メモリ破損の背後にある実際のメカニズムに特に興味があることを指摘する必要があります(SPのロールオーバーの結果ですか?>それはuCのメモリマッピングなどに依存しますか?)


8
無効なアドレスにアクセスしようとすると、一部のマイクロはリセットされます。これは、ハードウェアに実装されている貴重な機能です。場合によっては、任意の場所(ISRのリターンアドレスを破壊したなど)にジャンプし、アーキテクチャで許可されている場合はコードではなくデータを実行し、ウォッチドッグがそれをもたらすループに巻き込まれる可能性がありますの。
スペロペファニー

2
プロセッサがRAMを使い果たすことはできません。RAMを使い果たすようにする命令はありません。RAMの不足は完全にソフトウェアの概念です。
user253751

回答:


14

一般に、スタックとヒープは互いにクラッシュします。その時点でそれはすべて面倒になります。

MCUに応じて、いくつかのことが発生する(または発生する)可能性があります。

  1. 変数が破損する
  2. スタックが破損します
  3. プログラムが破損する

1が起こると、奇妙な振る舞いを始めます-物事が彼らがすべきことをしていない。2が起こると、あらゆる種類の地獄が崩れます。スタック上の戻りアドレス(ある場合)が破損している場合、現在の呼び出しがどこに戻るかは誰でも推測できます。その時点で、基本的にMCUはランダムな処理を開始します。3が再び発生すると、誰が何が起こるかをよく知っています。これは、RAMからコードを実行している場合にのみ発生します。

一般的に、スタックが破損すると、すべてが終了します。まさに何が起こるかはMCUにかかっています。

そもそもメモリを割り当てようとすると失敗するので、破損は発生しません。この場合、MCUは例外を発生させる可能性があります。例外ハンドラーがインストールされていない場合、ほとんどの場合、MCUは停止します(これに相当しwhile (1);ます。ハンドラーがインストールされている場合、クリーンに再起動する可能性があります。

メモリの割り当てが先に進む場合、またはメモリの割り当てが試行されて失敗し、メモリが割り当てられていない状態で続行する場合は、「誰が知っているのか」という領域にいます。MCUは、イベントの適切な組み合わせ(割り込みによってチップがリセットされるなど)によってリブートする可能性がありますが、その発生を保証するものではありません。

通常、発生する可能性が高いのは、有効になっている場合、内部ウォッチドッグタイマー(存在する場合)がタイムアウトし、チップを再起動することです。プログラムがこの種のクラッシュを完全に回避すると、通常、タイマーをリセットする命令は実行されないため、タイムアウトしてリセットされます。


あなたの答えをありがとう、それは効果の素晴らしい要約です。おそらく、これらの破損の実際のメカニズムの詳細が必要であることを指定する必要がありました:スタックポインタがロールオーバーして以前の変数/アドレスを上書きするように、RAM全体がスタックとヒープに割り当てられていますか?それとも、各マイクロのメモリマッピングへの依存度が低いですか?オプションで(おそらくそれ自体がトピックです)、これらのハードウェアハンドラーがどのように実装されているかを知りたいと思います。
ミスターミステア

1
ほとんどの場合、コンパイラと使用中の標準Cライブラリに依存します。また、コンパイラの構成方法(リンカースクリプトなど)に依存する場合もあります。
マジェンコ

おそらくいくつかの例を挙げて、それを拡張していただけますか?
ミスターミステア

そうでもない システムによっては、異なるセグメントに有限のスペースを割り当てますが、割り当てないシステムもあります。一部はリンカースクリプトを使用してセグメントを定義しますが、一部は使用しません。あなたに関心のあるマイクロコントローラを選択し、どのようにそのメモリ割り当ての作業にいくつかの研究を行う、。
Majenko

12

代替ビュー:マイクロコントローラーはメモリ不足になりません。

少なくとも、適切にプログラムされたときはそうではありません。マイクロコントローラーのプログラミングは、汎用プログラミングとまったく同じではありません。適切に行うには、その制約を認識し、それに応じてプログラミングする必要があります。これを確実にするツールがあります。それらを検索して学習します-少なくともリンカースクリプトと警告の読み方。

しかし、Majenkoらが言うように、不適切にプログラムされたマイクロコントローラーはメモリを使い果たしてから、無限ループ(少なくともウォッチドッグタイマーにリセットの機会を与えます。ウォッチドッグタイマーを有効にしましたか?) )

マイクロコントローラの一般的なプログラミングルールはこれを回避します。たとえば、すべてのメモリはスタックに割り当てられるか、静的に(グローバルに)割り当てられます。「new」または「malloc」は禁止されています。再帰も同様であるため、サブルーチンのネストの最大の深さを分析し、使用可能なスタックに収まるように表示できます。

したがって、プログラムがコンパイルまたはリンクされるときに必要な最大ストレージを計算し、ターゲットとする特定のプロセッサのメモリサイズ(リンカースクリプトでエンコードされることが多い)と比較できます。

その場合、マイクロコントローラーはメモリ不足にならないかもしれませんが、プログラムはそうかもしれません。そしてその場合、あなたは

  • 書き換える、より小さい、または
  • より大きなプロセッサを選択します(多くの場合、さまざまなメモリサイズで使用できます)。

マイクロコントローラプログラミングの一般的なルールセットの1つは、モーター業界で採用されているMISRA-Cです。

私の考えでは、AdaのSPARK-2014サブセットを使用するのがベストプラクティスです。Adaは、実際にはAVR、MSP430、ARM Cortexなどの小さなコントローラーをターゲットとしており、本質的にCよりもマイクロコントローラープログラミングの優れたモデルを提供します。

これで、SPARKツールはこれらの注釈を含むプログラムを分析し、そのプロパティを証明します(または潜在的なエラーを報告します)。誤ったメモリアクセスや整数オーバーフローに対処するために時間やコードスペースを無駄にする必要はありません。これらは決して発生しないことが証明されているからです。

SPARKにはより多くの先行作業が含まれますが、経験から、製品をより速く、より安価に入手できることが示されています。

MISRA-CとSPARKの比較


3
これに+1。AVRへmalloc()の移植(およびC ++コンパニオンnew)は、arduinoの人々が行うことができた最悪のことの1つであり、フォーラムとArduinoスタック交換の両方で壊れたコードを抱えた非常に多くの非常に混乱したプログラマーにつながりました。mallocATmegaを使用することが有益な状況はほとんどありません。
コナーウルフ

3
哲学の場合は+1、リアリズムの場合は-1。ものが適切にプログラムされていれば、この質問は必要ありません。問題はマイクロコントローラーのメモリが不足するとどうなるかでした。メモリ不足を防ぐ方法は別の問題です。別の注意として、再帰は問題の解決スタック不足のための強力なツールです。
PkP

2
@ブライアン、私はバカではないので、明らかにあなたに同意します。私はそれを逆の視点で考えたいです-メモリ不足(スタック)の恐ろしい結果に気付いたとき、それを防ぐ方法を模索することを望みます。そうすれば、良いプログラミングのアドバイスに従うだけでなく、優れたプログラミングの実践を見つけることに向けて真の推進力があります...そして、メモリの壁にぶつかると、利便性を犠牲にしてでも良い実践を実施する可能性が高くなります。それは単なる視点です...
PkP

2
@PkP:大声でクリアに聞こえます。私はこれを別のビューと名付けました-それは実際に質問に答えていないからです!
ブライアンドラモンド

2
@MisterMystère:マイクロコントローラーは通常、メモリ不足になりません。最初に電源を入れたときに4096バイトのRAMを備えたマイクロコントローラーは、永久に4096バイトになります。コードが誤って存在しないアドレスにアクセスしようとしたり、アドレスを計算する2つの異なる方法が異なるメモリにアクセスすると予期したりする可能性がありますが、コントローラー自体は与えられた命令を実行するだけです。
-supercat

6

私はMajenkoの答えが本当に好きで、自分で+1しました。しかし、私はこれをはっきりさせたいと思います:

マイクロコントローラのメモリが不足すると、も起こりません。

それが起こるとき、あなたは本当に何にも頼ることができません。マシンがスタックメモリを使い果たすと、おそらくスタックが破損します。そしてそれが起こると、何でも起こります。変数値、流出、一時レジスタはすべて破損し、プログラムフローを中断します。If / then / elsesが誤って評価される可能性があります。リターンアドレスが文字化けし、プログラムがランダムアドレスにジャンプします。プログラムで作成したコードは実行できます。(「if [condition] then {fire_all_missiles();}」のようなコードを検討してください)。また、コアが接続されていないメモリ位置にジャンプしたときに、記述していない一連の命令を実行できます。すべてのベットはオフです。


2
補遺をありがとう、私は特にfire_all_missiles()行が好きでした。
ミスターミステア

1

AVRはアドレス0でベクトルをリセットしました。スタックをランダムなガベージで上書きすると、最終的にループして戻りアドレスを上書きし、「nowhere」を指します。その後、サブルーチンからどこにも戻らないと、実行は、リセットハンドラへのジャンプが通常行われるアドレス0にループします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.