stack - memory-management - Windows 10 address space - スタックとヒープはどこに何があるのか?

Linux arm64 memory map / memory-management / language-agnostic / heap / dynamic-memory-allocation

プログラミング言語の本では、値型はスタック上に作成され、参照型はヒープ上に作成されると説明されていますが、これら2つのことは説明されていません。私はこれについての明確な説明を読んでいません。スタックとは何かを理解しています。だが、

RajeshKdev



Answer #1

これらすべてを説明するために、簡単な注釈付きのCコードを提供します。学ぶための最良の方法は、デバッガの下でプログラムを実行し、その動作を見ることです。パイソンを読みたい方は、回答の最後まで読み飛ばしてください :)

//プログラム/ DLLが最初にロードされたときにデータセグメントに静的に割り当てられます
//プログラム/ DLLの終了時に割り当てが解除されます
//スコープ-コード内のどこからでもアクセスできます
int someGlobalVariable;

//プログラムが最初にロードされたときにデータセグメントに静的に割り当てられます
//プログラム/ DLLの終了時に割り当てが解除されます
//スコープ-この特定のコードファイルのどこからでもアクセスできます
static int someStaticVariable;

// MyFunctionが呼び出されるたびに、「someArgument」がスタックに割り当てられます
// MyFunctionが戻ると、「someArgument」の割り当てが解除されます
//スコープ-MyFunction()内でのみアクセスできます
void MyFunction(int someArgument) {

    //プログラムが最初にロードされたときにデータセグメントに静的に割り当てられます
    //プログラム/ DLLの終了時に割り当てが解除されます
    //スコープ-MyFunction()内でのみアクセスできます
    static int someLocalStaticVariable;

    // MyFunctionが呼び出されるたびにスタックに割り当てられます
    // MyFunctionが戻ったときに割り当てが解除されました
    //スコープ-MyFunction()内でのみアクセスできます
    int someLocalVariable;

    // MyFunctionが呼び出されるたびに*ポインタ*がスタックに割り当てられます
    // MyFunctionが戻ると、このポインタの割り当てが解除されます
    //スコープ-ポインタはMyFunction()内でのみアクセスできます
    int* someDynamicVariable;

    //この行により、整数用のスペースがヒープに割り当てられます
    //この行が実行されたとき。これは最初ではないことに注意してください
    //自動変数のように、MyFunction()の呼び出し
    //スコープ-MyFunction()内のコードのみがこのスペースにアクセスできます
    // *この特定の変数を介して*。
    //ただし、アドレスを別の場所に渡すと、そのコード
    //アクセスすることもできます
    someDynamicVariable = new int;


    //この行は、ヒープ内の整数のスペースの割り当てを解除します。
    //書き込まなかった場合、メモリは「リーク」されます。
    //スタックとヒープの根本的な違いに注意してください
    //ヒープを管理する必要があります。スタックは私たちのために管理されています。
    delete someDynamicVariable;

    //その他の場合、このヒープスペースの割り当てを解除する代わりに、
    //後で使用するために、アドレスをより永続的な場所に格納する場合があります。
    //一部の言語では、割り当て解除も処理されます...しかし
    //常に何らかのメカニズムによって実行時に処理する必要があります。

    //関数が戻ると、someArgument、someLocalVariable
    //およびポインタsomeDynamicVariableの割り当てが解除されます。
    // someDynamicVariableが指すスペースはすでに存在していました
    //戻る前に割り当てを解除します。
    return;
}

// someGlobalVariable、someStaticVariable、および
// someLocalStaticVariableは引き続き存在し、存在しません
//プログラムが終了するまで割り当てを解除します。

C/C++の構文のいくつかは、この問題を悪化させます。例えば、多くの人は、グローバル変数は「静的」ではないと考えていますが、これは以下のような構文によるものです。

int var1; //グローバルスコープと静的割り当てがあります
static int var2; //ファイルスコープと静的割り当てがあります

int main() {return 0;}

これらの概念をC/C++特有のものと考える人がいます。そうではありません。例えば,以下のPythonのサンプルでは,3つのタイプのアロケーションがすべて示されています(インタプリタ言語では微妙な違いがありますが,ここでは触れません).

from datetime import datetime

class Animal:
    _FavoriteFood = 'Undefined' #_FavoriteFoodは静的に割り当てられます

    def PetAnimal(self):
        curTime = datetime.time(datetime.now()) #curTimeは自動的に割り当てられます
        print("Thank you for petting me. But it's " + str(curTime) + ", you should feed me. My favorite food is " + self._FavoriteFood)

class Cat(Animal):
    _FavoriteFood = 'tuna' #オーバーライドするため、Catクラスには、Animalとは異なり、静的に割り当てられた独自の_FavoriteFood変数があることに注意してください。

class Dog(Animal):
    _FavoriteFood = 'steak' #同様に、Dogクラスは独自の静的変数を取得します。注意すべき重要な点-この1つの静的変数は、Dogのすべてのインスタンス間で共有されるため、動的ではありません。


if __name__ == "__main__":
    whiskers = Cat() #動的に割り当てられる
    fido = Dog() #動的に割り当てられる
    rinTinTin = Dog() #動的に割り当てられる

    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

    Dog._FavoriteFood = 'milkbones'
    whiskers.PetAnimal()
    fido.PetAnimal()
    rinTinTin.PetAnimal()

#出力は次のとおりです。
#私をかわいがってくれてありがとう。しかし、それは13:05:02.255000です、あなたは私を養うべきです。私の好きな食べ物はマグロです
#私をかわいがってくれてありがとう。しかし、それは13:05:02.255000です、あなたは私を養うべきです。私の好きな食べ物はステーキです
#私をかわいがってくれてありがとう。しかし、それは13:05:02.255000です、あなたは私を養うべきです。私の好きな食べ物はステーキです
#私をかわいがってくれてありがとう。しかし、それは13:05:02.255000です、あなたは私を養うべきです。私の好きな食べ物はマグロです
#私をかわいがってくれてありがとう。しかし、それは13:05:02.255000です、あなたは私を養うべきです。私の好きな食べ物はミルクボーンです
#私をかわいがってくれてありがとう。しかし、それは13:05:02.256000です、あなたは私を養うべきです。私の好きな食べ物はミルクボーンです