58

重複の可能性:
スタックとヒープはどこにありますか?

acプログラムのメモリレイアウトの基本的な概念に関して、私はそれを理解しています:

  • この言語は、2つの主要なデータ構造のスタックヒープを使用します。
  • スタックは、ローカル変数を格納し、サブルーチンのデータを保持するために作成されます
  • ヒープは、プログラムの動的に割り当てられた変数を格納するために作成されます
  • ヒープは本質的に可変長です(スタック上ではよくわかりません)
  • 通常、実行前にこれらのデータ構造を作成するようにOSに要求するのは、コンパイラ/言語の責任です。

質問

  • スタック/ヒープが作成される初期サイズはどれくらいですか?そして誰がそれを決めるのですか?
  • それらはどこで物理メモリが作成されますか?「スタックは最上位アドレスに作成され、ヒープは下位レベルアドレスに作成されます」という一般的な説明が表示されます。これを詳しく説明してください
4

4 に答える 4

66

「スタックは最上位アドレスに作成され、ヒープは下位レベルアドレスに作成されます」これを詳しく説明してください

これは神話です。それは歴史的真実の基礎を持っているかもしれません。実生活で目にするものと共鳴することもあります。しかし、それは文字通り真実ではありません。

ただし、探索するのは簡単です。

#include <stdlib.h>
#include <stdio.h>

void check(int depth) {
    char c;
    char *ptr = malloc(1);
    printf("stack at %p, heap at %p\n", &c, ptr);
    if (depth <= 0) return;
    check(depth-1);
}

int main() {
    check(10);
    return 0;
}

私のマシンでは、次のように表示されます。

stack at 0x22ac3b, heap at 0x20010240
stack at 0x22ac0b, heap at 0x200485b0
stack at 0x22abdb, heap at 0x200485c0
stack at 0x22abab, heap at 0x200485d0
stack at 0x22ab7b, heap at 0x200485e0
stack at 0x22ab4b, heap at 0x200485f0
stack at 0x22ab1b, heap at 0x20048600
stack at 0x22aaeb, heap at 0x20048610
stack at 0x22aabb, heap at 0x20048620
stack at 0x22aa8b, heap at 0x20048630
stack at 0x22aa5b, heap at 0x20048640

したがって、スタックは下向きになり、ヒープは上向きになります(神話に基づいて予想されるように)が、スタックのアドレスは小さく、互いに向かって成長していません(神話は破綻しています)。

ところで、私のcheck関数は末尾再帰であり、いくつかのコンパイラオプションを使用した一部の実装では、スタックがまったく移動しない場合があります。これは、標準がこれらすべてがどのように機能するかを義務付けていない理由について何かを教えてくれます-もしそうなら、それが不注意に有用な最適化を禁止するかもしれません。

于 2012-10-02T10:33:59.360 に答える
17

すでに述べたように、サイズはOS固有です。たとえば、Visual Studioを使用するWindowsの場合、デフォルトのスタックサイズは1MBです。

msdn

Linuxでは、次のコマンドで現在のコマンドを表示できます。

ulimit -s or -a

私のLinuxmint64ビットでは、8192KBを示しています。

メモリにロードされたときのすべてのプログラムには、いくつかのセグメントがあります。アセンブリでは、.data、.codeなどのプレフィックス(intelx86)を使用してそれぞれを示すことができます。

これは、いくつかのサブセクションを持つデータセグメントです。スタックとヒープの両方が、他のいくつかに加えてその一部です。

スタックは暗黙的に大きくなることもあります。つまり、別の関数呼び出しを行うと、アクティベーションレコードがスタックにプッシュされ、スタックのメモリをより多く使用します。そのため、プログラムが割り当てられたスタックを使い果たすと、無限再帰によってクラッシュが発生します。

関数呼び出しが戻ると、そのアクティベーションレコードがポップされ、スタックが縮小します。

対照的に、ヒープは反対方向から成長し、動的に割り当てられたすべてのメモリを含みます。

これらの2つのセグメントが反対方向に成長する理由は、それらを組み合わせたメモリの使用率を最大化するためです。コメントで述べたように、これはAC標準ではありませんが、ほとんどの一般的なOSにはこれが実装されていることに注意してください。

------スタックが開始します-----------スタックが下に成長します

--------互いに交差しない限り、プログラムは実行できます。

-------ヒープが開始します------------ヒープが上向きに成長します

プログラムがヒープを使用しない場合、スタックはヒープのメモリも含めて最大のメモリを利用できます。プログラムが再帰呼び出しをほとんど行わず、最小限のローカル変数を使用する場合(つまり、スタックに使用するメモリが少ない場合)、ヒープを最大限に活用できます。

データセグメントの他の部分は、初期化されていない静的変数などのフィールドを含む可能性のあるBSSなどです。

于 2012-10-02T09:08:53.180 に答える
10

スタック/ヒープが作成される初期サイズはどれくらいですか?そして誰がそれを決めるのですか?

これはコンパイラおよびOSに固有です。

それらはどこで物理メモリが作成されますか?一般的な説明は、「ヒープは最上位アドレスに作成され、スタックは下位レベルアドレスに作成される」と表示されます。

これはコンパイラおよびOSに固有です。

本当に。言語標準では、最小スタックサイズが義務付けられておらず、メモリ内のスタックまたはヒープの場所も指定されていません。その理由は、Cプログラムがこれらの詳細に依存することが少なくなり、したがって、さまざまなプラットフォーム(さまざまなOS、さまざまなCPU、さまざまなコンパイラー)への移植性が向上するためです。

于 2012-10-02T09:04:23.577 に答える
5

まず第一に、C標準は、スタック/ヒープがプラットフォームによってどのように実装されるかについての要件を課していません。

What is the initial size with which a stack/heap is created? and who decides it?

通常、固定サイズのスタックは、プラットフォーム固有のOSによってすべてのプロセスに割り当てられます。ヒープサイズに制限はありません。プログラムには通常、使用可能なすべての仮想アドレス空間があります。

Wherein physical memory are they are created?

これはプラットフォーム固有です。通常、スタックは下向きに成長し、ヒープは上向きに成長します。

于 2012-10-02T09:10:29.080 に答える