2015-09-30 29 views
11

プログラムメモリ割り当て

#include<stdio.h> 
int a=10; 
void main() 
{ 
    int i=0; 
    printf("global = %p, local = %p\n",&a,&i); 
    main(); 
} 

出力

[email protected]:~/Advanced_Unix/Chapter7$ ./a.out 
global = 0x804a014, local = 0xbfff983c 
global = 0x804a014, local = 0xbfff980c 
. 
. 
. 
global = 0x804a014, local = 0xbf7fac9c 
global = 0x804a014, local = 0xbf7fac6c 
global = 0x804a014, local = 0xbf7fac3c 
Segmentation fault (core dumped) 
[email protected]:~/Advanced_Unix/Chapter7$ 

上記のプログラムは、セグメンテーションフォールトエラーを取得します。なぜなら、メインは再帰的に自身を呼び出すからです。以下は、Cプログラムへのメモリ割り当て の割り当てです。

メモリ割り当て

  __________________      __________________ 
      |    |      |    | 
      |  stack  |      |  Main  | 
      | ↓    |      |----------------| 
      ------------------      |  Main  | 
      |    |      |----------------| 
      | <Un Allocated|      |  Main  | 
      |  space> |      |----------------| 
      ------------------      |  Main  | 
      |    |      |----------------| 
      | ↑   |      |  Main  | 
      |  Heap  |      |----------------| 
      |    |      |  Main  | 
      |    |      |----------------| 
      __________________      |////////////////| ---> Collision occurs. So, Segmentation fault Occurs. 
      |    |      |________________| 
      |  data  |      |  data  | 
      __________________      |________________| 
      |  text  |      |  text  | 
      __________________      |________________| 
       Figure(a)        Figure(b) 

だから、私は再帰的に、図(B)のように示されているメイン呼び出しを期待します。データセグメントに到達すると、衝突が発生します。 これが発生した場合、main関数に割り当てられるスペースがなくなります。したがって、セグメント化エラーが発生します。上記のプログラムを使って実験します。 そのプログラムでは、グローバル変数 'a'のアドレスは「0x804a014」です。 mainが呼び出されるたびに、ローカル変数 "i"が宣言されます。だから、私は セグメンテーションフォールトの前に、私のアドレスはほぼ 'a'のアドレスになると期待しています。しかし、両方のアドレスは非常に異なっています。ここで何が起こっているのですか?

セグメンテーションフォールトエラー時に 'a'と 'i'のアドレスが同じ範囲にないのはなぜですか。だから、 メインがスタックサイズに達してオーバーフローするかどうかをどうやってチェックするか?

+5

プログラムを一時停止し、 '/ proc/pid/maps'を見てください。そこにはライブラリのようなものがあります。加えて、スタックサイズ(ulimit)に実際の制限があります – Petesh

+0

ライブラリのオブジェクトのアドレスを1つ印刷できますか?言って、&stdin?または標準ですか? –

+0

@Peteshこれはスタックサイズです:bf99c000-bfa39000 rw-p 00000000 00:00 0 [スタック] – mrg

答えて

0

'a'はグローバル変数であり、スタックには入れません。これはデータセクションにあります - つまり、初期化されたbss

'i'はローカル変数であり、スタックに格納されます。

これらは全く異なるセクションであり、その違いがあります。あなたが書いたとき

Global memory management in C++ in stack or heap?

0

を参照してください変数「i」が、あなたが正しい何かを書いていると宣言されますが、変数はグローバルaとして宣言されていません。

iはスタック割り当てであり、スタックは独自のサイズを持っています。

ulimitこの制限を変更することができます。

グローバル変数のアドレス割り当てとローカル変数のアドレス割り当ての間に、の衝突があります。

1

あなたのスキーマは、概念モデルまたは実装の可能性があります。しかし、例えば、マルチスレッドのプログラムでは、スレッドごとに1つのスタックがあり、シンプルなスキーマに実際には収まらない単一のヒープが1つあります。

すべての必要なことは、システムが再帰を許可するということです。つまり、関数の新しい呼び出しごとにローカル変数のプライベートコピーが得られます。残っていることは実装に依存します。

最近のシステム利用ページの割り当て、およびプロセスは、一般的にページ・セグメントのセットを取得しますが、それらは必ずしも連続しておらず、そして、あなたが持つことができる穴すべてのアクセスがSIGSEGV(セグメント違反)を取得しますそれらの間の

TL/DR:プログラムは、静的変数のアドレスに到達するダイナミック変数のアドレスよりもSIGSEGV信号を受け取る可能性が高くなります。このような動作を行うには、古いMS/DOSボックスが必要です。

0

あなたが持っている記憶モデルは、巨大な過度の単純化であり、学生の記憶の基礎を教え始めるだけで、デタでそれらを圧倒しないようにするのに便利です最初はils。ちょうど私たちが自然数を加えて数学教育を始めるように。それは良い基盤ですが、あなたが現実を理解するためにそれを使うならば、あなたを遠ざけることはありません。

このモデルは少なくとも25-30年間正確ではなく、実際のプログラムの動作に関する予測に使用することはできません。ヒープとスタック(共有ライブラリ、大きなmalloc、ファイルのmmapなど)の間には、他にも何千ものメモリマッピングがあります。 "ヒープ"の概念は、オペレーティングシステムがあらかじめ知っていなかった目的のために、アドレス空間のどこにでも匿名メモリの動的割り当ての合計をあまり上回らないため、非常に問題が多い。

あなたの例では、スタックリソース制限(ulimit -sを参照)が実行されています。