メモリ制限の厳しい組込み環境
症状の発生
typedef struct {
float valA;
float valB;
float valC;
} dataType_t;
上記のような構造体を定義しているとする。それを以下のように、「RTOSのとあるタスク内の関数で使用しているとする」
void funcSome(){
dataType_t myData;
この状態で、「valD-valIを追加してください」と言われて追加するとする。
typedef struct {
float valA;
float valB;
float valC;
#if 1 // added
float valD;
float valE;
float valF;
float valG;
float valH;
float valI;
#endif
} dataType_t;
実行するとプログラムが途中から動かなくなる。
理由は以下の通り。
関連 メモリの4領域
RTOSのタスクにおいては、そのタスクに割り当てるメモリサイズを指定する(例: 256バイト)。タスク内で使用する関数(funcSome())の自動変数はそのメモリを消費して動く。
上記の例ではdataType_t myData;
として定義したmyDataはタスクで割当てたメモリ[スタック領域]を消費して動くが、項目数が増えた時に割当てたメモリサイズを超えてしまう場合がある。そうなるとメモリ破壊が生じてプログラムの動作が途中からおかしくなる。
対策
static付加
1つの対策としては
void funcSome(){
dataType_t myData;
を以下のようにする。
void funcSome(){
static dataType_t myData;
staticをつけることで、メモリの4領域に記載の「スタック領域」の使用から「静的領域」での使用に変更する。
タスク割当てメモリの増加
別の方法としてはタスク割当てメモリサイズを増やす、ということも考えられる。
dataType_t のサイズの増加分を増やす。
staticを付加するのか、タスク割当てメモリを増やすのかは、状況による。
デバッグの難しさ
メモリ破壊が起きた時点は正常に動いている。
問題は破壊が起きた部分を読みだしてからの動作になるが、その発生を追うのは難しいように思う。
RTOSを使っていて、項目を増やしてから動作が途中で止まるようになった時、上記のような現象を疑うというのも一つの手と思われる。
こういう症状は一度経験すると再現した時に対策をすぐに思いつくが、一度も経験していない人にとっては「何が起きたか分からない」状態になり、数分のデバッグで済まなくなる。