スタックメモリについて

解決済みの質問

スタックメモリについて

プログラムの起動時に、スタックメモリは初期化(NULLに設定)されるのでしょうか。
PUSH・POPで使用したらデータは残りますが、未使用の場合、初期化されているかの質問です。

グローバル変数の領域はクリアされると思われますが、スタックは不明です。
クリアされないときは、ほかのプログラムで使用されたゴミデータが
残っているのでしょうか

目的は、スタック領域でメモリ障害の場合動作が変わってしまうのか、確認したいためです。

すいませんが、よろしくお願いします。

投稿日時 - 2010-11-25 23:43:48

QNo.6344200

困ってます

質問者が選んだベストアンサー

初期化していない変数の初期値は、言語仕様によりますが、
スタック領域に定義される変数は、たいていの言語で、初期値は不定です。

更に言えば、最後に使われた「不明」な値が残っていることでもなく、
Cの関数、JAVAのメソッドが呼び出される都度、初期値はランダムに変化するので、
「不明」ではなく、まさに「不定」です。


何故ランダムに変化するかについてですが、
まず、スタック領域の説明です。

スタック領域は、一時的な値の保存場所です。
スタックポインタによって管理されており、
スタックポインタが指しているアドレスより下(高位)は使用中、
上(低位)は使用可能となっています。

使用可能
========================== <= スタックポインタ
使用中

そして、使用可能領域は、常に割り込みルーチンにより使用されているので、
常時書き換わっています。


割り込みとは、キーが押された、マウスが動いた、通信データが受信された、
時間が経過した、等の、プログラムとは直接関係ないイベントのことで、
その発生時には、実行中のプログラムに割り込んで、
必要な処理(キーを読む、マウスポインタを動かす、通信データを読む等)を行い、
その後は何事もなかったかのように、元のプログラムの実行が継続されます。

しかし、元のプログラムの実行を継続させるためには、
割り込み時の状態をどこかに保存し、終了時には復元する必要があるわけで、
その際にスタック領域が使われます。

割り込みが発生した際のスタックの動きは以下の通りです。

- 戻りアドレスがスタックにpushされる
- フラグがスタックにpushされる
- 割り込みルーチンが呼び出される
- 保存の必要なレジスタがスタックにセーブされる
- 作業領域を確保する

- 割り込みの処理後、レジスタが復元される
- フラグが復元され、戻りアドレスに戻る、同時にスタックポインタが戻される


========================== <= 割り込み中のスタックポインタ
作業領域

--------------------------
レジスタ退避

--------------------------
フラグ
--------------------------
戻りアドレス
========================== <= 割り込み前後のスタックポインタ
使用中


話を戻しますが、プログラムでも、Cの自動変数、JAVAのローカル変数のような
一時的な変数は、スタック領域に定義されます。

C言語の例ですが、

sub(int a, int b)
{
int c,d;

の場合、関数が呼び出される際のスタックの動きは以下の通りです。

- パラメータ a, b がスタックにpushされる
- 戻りアドレスがスタックにpushされる
- 関数subが呼び出される
- 保存の必要なレジスタがスタックにセーブされる
- c, d の領域がスタックに確保される

- 関数の処理後、レジスタが復元される
- 戻りアドレスに戻る
- スタックポインタが呼び出し前の値に戻される


========================== <= 関数処理中のスタックポインタ
d
--------------------------
c
--------------------------
レジスタ退避

--------------------------
戻りアドレス
--------------------------
a
--------------------------
b
========================== <= 関数呼び出し前のスタックポインタ
使用中

c, d については、領域を確保する(スタックポインタを減らす)だけで
初期化はしないので、その時のメモリの内容が初期値になります。

そして、前述のように、使用可能なスタック領域は、
常に割り込みルーチンによって書き換えられているので、
以前の値が残っていることもなく、実行する都度、初期値が変わる「不定」です。


>目的は、スタック領域でメモリ障害の場合動作が変わってしまうのか、確認したいためです。

マルチタスクOSの場合、メモリも仮想化されているので、
プログラムが認識するメモリと物理的なメモリとは、直接の対応はないし、
メモリ障害の場合、たいていはその場でシステムダウンになります。

また、スタック領域の変数の初期値が、実行するたびに違うということなら、
スタックの性質上、それが正しい動作であり、メモリの障害ではありません。

投稿日時 - 2010-11-26 10:42:24

お礼

有難うございます。
参考にさせていただきます。

投稿日時 - 2010-11-28 14:24:22

ANo.4

2人が「このQ&Aが役に立った」と投票しています

[  前へ  |  次へ ]

ベストアンサー以外の回答(3件中 1~3件目)

ANo.3

明示的にプログラムで何もしていなければコンパイラ次第です。

> スタック領域でメモリ障害の場合動作が変わってしまうのか

意図をはかりかねますが、ゼロクリアしていようがいまいが、PUSHしていないスタックをPOPしたら不正動作ですし、書き換えられたスタックをPOPすれば何が起きても不思議はないですよね。
スタック回りの障害を考えるなら、スタック自身だけでなくスタックポインタも疑う必要があります。

投稿日時 - 2010-11-26 09:25:14

ANo.2

スタックの初期化などはされませんので不定の値です。
変数も初期値のないものは全て不定です。グローバル、ローカルの区別無しに。

>目的は、スタック領域でメモリ障害の場合動作が変わってしまうのか、確認したいためです。
意図がよくわかりませんが。メモリ障害の箇所にアクセスしたら例外発生でしょうね。

投稿日時 - 2010-11-26 03:06:16

ANo.1

言語が不明なので C と想定する.
「スタックメモリ」なるものは規格にはありませんので, 「スタックメモリが初期化されるかどうか」ももちろん決まっていません.
「スタックメモリ」を使う多くの処理系で初期化子を指定しない場合は初期化しないと思いますが, その辺は上に書いたように規格で決まっていることではないので処理系に聞いてください.
あと, 「初期化」と「NULL に設定」とは違います. もちろん, ポインタでないものを「NULL に設定する」というのはプログラムとして間違ってます.

投稿日時 - 2010-11-25 23:57:06

あわせてチェックしたい
  • グローバル変数の初期化のタイミング ...
  • C言語のグローバル変数の初期化について ...
  • スタックとキューの違いを示すプログラム。 ...
PR

OKWaveのオススメ

教えて弁護士さん!

お金の悩みQ&A特集はこちら