2013-07-14 5 views
11

私の教授は、プログラムがメモリ上でどのように見えるのか混乱しています。私の教授は、スタックとヒープは、スタックがより低いメモリアドレスになるようにお互いに向かって成長すると言いました。linuxのプログラムメモリのレイアウト

最初に私が気になったのは、ヒープが高から低になった場合、ヒープ上に配列を割り当てた場合、2番目の要素へのポインタは、最初の要素?これは、私は少し研究を行なったし、データと未初期化されたデータは、テキストの後に来るので、私は、[OK]を

layout http://www.cyberplusindia.com/blog/wp-content/uploads/2008/10/memorysegment.gif

(私の質問は、Linux上で重視されています)この図に出くわしました

混乱するでしょうセグメントの先頭にあり、プログラムのメモリの先頭にあり、ヒープの後にスタックがあり、最後にコマンドラインの引数と環境が続きます。

しかし、スタックが高アドレスから低位に成長する場合、スタックに割り当てられた配列があると、最初の要素へのポインタも2番目の要素へのポインタよりも値が低くなりますか?スタックが低から高にも成長することを意味していませんか?

私の質問は、Linuxのプロセスの正しいメモリレイアウトは何ですか?ポインタの例でも、共有ライブラリ用のメモリは、(プロセス内のアドレス空間)から来たんどこ

シンプルコード:

#include <iostream> 


int data[5]; 

int main() 
{ 
    using std::cout; 
    using std::endl; 
    int stack = 0; 
    short *sptr = reinterpret_cast<short *> (&stack); 
    int *iptr = new int[5]; 
    cout << "Starting static tests" 
     << "\nPointer to first element " << data 
     << "\nPointer to second element " << &data[1] 
     << "\nstarting stack test " << sptr 
     << "\nsecond short " << &sptr[1] 
     << "\nStarting heap test " << iptr 
     << "\nsecond int " << &iptr[1]; 
    delete[] iptr; 
    return 0; 
} 

出力:

Starting static tests 
Pointer to first element 0x6013e0 
Pointer to second element 0x6013e4 
starting stack test 0x7fffdf864dbc 
second short 0x7fffdf864dbe 
Starting heap test 0x1829010 
second int 0x1829014 

答えて

3

もしIスタックに配列が割り当てられている場合、最初の要素へのポインタも2番目の要素へのポインタよりも値が小さいでしょうか?

アレイを割り当てる方法は重要ではありませんが、スタックポインタを増減することはできますが、その結果、アレイ用に予約されたアドレススペースが得られます。

最低の住所がそのように私の質問は、Linuxでのプロセスのための正しいメモリレイアウトは何かある要素0

のために予約されているので、あなたは、通常の方法で彼らと仕事ができますか?

自分で確認できます。あなたのプログラムのどこかに のようなものを挿入して、std::cin.get()のようにプログラムを一時停止してください。

はその後、別のシェルで実行します。

ps aux | grep your_program_name 
cat /proc/<pid show by grep>/maps 

これは、ヒープ、スタックや他のものは、メモリに配置されている場所を確認することができ、あなたのプロセスのメモリマッピングを出力します。

スタックについて:LinuxとIntelまたはAMD 64ビットCPUを搭載した通常のマシンがあるとします。そして、次のコードを記述します。

extern void f(int); 

void g(int param) 
{ 
    f(param); 
} 

を、それをコンパイルし、逆アセンブル:

g++ -ggdb -c test_my_stack.cc && objdump -S test_my_stack.o 

あなたが見ることができます(重要でない詳細は削除):

void g(int param) 
{ 
0: 55      push %rbp 
1: 48 89 e5    mov %rsp,%rbp 
4: 48 83 ec 10    sub $0x10,%rsp 
8: 89 7d fc    mov %edi,-0x4(%rbp) 
    f(param); 
b: 8b 45 fc    mov -0x4(%rbp),%eax 

あなたがsub $0x10,%rspで見ることができるように、我々はスペースを予約スタックポインタを減少させる(下に移動する)ことによって、スタック内に格納される。その画像を私に気

+0

私はそれが間違って読んでいない限り、私は[ヒープ] RW-P 00000000 0時00分0 016ea000-0170b000 スタックとヒープの両方がローからハイに成長する私の質問の例プログラムのマップをチェックアウトし、 7fffe828a000-7fffe82ab000 rw-p 00000000 00:00 0 [スタック] 途中で.soがたくさんあり、環境とCLAのために予約された場所を見つけることができないようです[地図付きの要点](https:// gist .github.com/ah450/5992828) –

+0

ええ私は完全にespを忘れていましたので、高から低へと成長するはずですが、スタック上に作成された整数への短いポインタを作成するとどうなりますか?秒よりもアドレスが低いですか?または私は何かを逃している? –

+0

コンパイラコードによって生成されるため、値ごとにスタックを割り当てないため、すべてを一度に割り当てます。あなたのプログラムでは、0x50バイトを割り当てようとすると、スタック変数が "-0x34(%rbp)"、 "sptr"が-0x8(%rbp)なので、(uint8_t *)&stack <(uint8_t *) &sptr。これは、スタックポインタを関数ごとに1回だけ減らすためです。 – fghj

2

まず最初は、ヒープがハイからローに成長した場合、私はヒープ上にアレイを割り当てられた場合、第2の要素へのポインタがポインタよりint値が小さくてはならないということです最初の要素に?それは混乱するでしょう。

まったくありません。たとえば、メモリプールから10バイトの配列を割り当て、高から低になるとします。アロケータが行う必要があるのは、そのメモリプールの「ボトム」を10だけ減らし、その値を割り当てられた配列の先頭として使用することです。配列は古い "底部"で終了します。ポインタの算術演算は期待どおりに動作しますが、低いアドレスに向かって "成長"します。

関連する問題