|
メモリスタック
メモリスタックまたはスタックメモリという言葉を聞いたことはありますか?ある程度大きなプログラムを作る場合はこの辺の知識が必要になってきます。
Cのプログラムでメモリを使う場合、大きく分けて、
・ローカル変数(Auto変数)
・グローバル変数
・動的に確保するメモリ領域(mallocなどで確保するメモリ)
の3種類があります。
このうち、ローカル変数がスタックメモリに置かれます。ではスタックメモリとは何でしょうか。その前に関数について考えてみましょう。Cの関数は、呼び出されると、関数スタックというメモリ領域に関数ポインタが置かれます。関数が終了すると関数スタックから削除されます。
Cのプログラムはmain関数から別の関数を呼んで、またその関数の中から別の関数を呼んで…というような流れでプログラムが実行されていきます。関数スタックというのは関数の呼び出し履歴みたいなものですね。
たとえばAという関数からBという関数を呼んで、BからCという関数が呼ばれるとすると、関数スタックは、Aを追加
-> Bを追加 -> Cを追加 -> Cを削除 -> Bを削除 -> Aを削除という順番に処理が行われます。ここでひとつの特徴があることがわかりますか?最初に追加したものは最後に削除されて、最後に追加したものは最初に削除されるということです。このように「先入れ後出し(FILO)」のアルゴリズムのことを「スタック」と言います。
さて、ローカル変数というのは、その関数が呼び出されると確保されて、関数が終了すると自動的に開放されます。これは関数スタックの追加/削除のタイミングと一緒なので、ローカル変数もまた、確保/開放のアルゴリズムがスタック構造になっています。
では本題に入りましょう。このスタックメモリというものは通常、動的に確保するメモリに比べて非常にサイズが小さいです。固定サイズなので当然ですね。使わないのに何ギガもあったらメモリの無駄遣いですよね。VCでは、このサイズはデフォルトで1MBです。
プログラムを書くときの基本方針として「スタックメモリの使用は必要最小限にする」ということを心がけましょう。ちなみにスタックオーバーフローすると、プログラムが強制終了します。
たとえば、文字列用のバッファを次のように確保する人がよくいます。
int main(int argc, char *argv[])
{
char str[256];
// メイン処理...
return 0;
}
|
これはあまりよくありません。Windowsならまだいいですが、メモリ量の少ないモバイル機器などではまずこのような確保の仕方はしないほうがいいでしょう。Windowsであっても、この関数が4000回、再帰処理で呼び出されるとスタックオーバーフローします。
この場合は、動的に確保するかグローバル変数を使うようにします。(C++では動的な文字列クラスを使うようにしましょう)
また、構造体をローカル変数にとる時は、構造体のサイズに注意しましょう。構造体1つで1MBもサイズがあったら、それだけでスタックを使い果たしますので^^;。
|