良い記事の転載: ヒープとスタックの違いは何ですか?


シンプルは次のように理解できます: 
ヒープ: malloc などの関数によって割り当てられたスペースの場所。アドレスは低いものから高いものへと成長します。 
スタック: 関数が呼び出されたときに使用される変数とスペースを自動的に割り当てることです。アドレスは上位から下位に減少します。 


予備知識 - プログラムメモリの割り当て c/C++でコンパイルされたプログラムが占有する

メモリは、次の部分に分割されます。 
. データ構造のスタックのように動作します。 
2. ヒープ領域 (ヒープ) - 通常、プログラマーによって割り当てられ、解放されます。プログラマーが解放しない場合、プログラムの終了時に OS によって回復される可能性があります。データ構造のヒープとは異なり、割り当て方法は連結リストに似ていることに注意してください(笑)。 
3. グローバル領域 (静的領域) (静的) - グローバル変数と静的変数の格納場所がまとめられ、初期化されたグローバル変数と静的変数が同じ領域にあり、初期化されていないグローバル変数と初期化されていない静的変数が同じ領域にあります。別の隣接エリア。- プログラムの終了後にシステムによって解放されます 
4. リテラル定数領域 - 定数文字列がここに配置されます。プログラムの終了後にシステムによって解放される 
5. プログラム コード領域 - 関数本体のバイナリ コードを格納します。 

2. プログラム例 
これは先輩が書いた非常に詳細な 
//main.cpp 
int a = 0; グローバル初期化領域 
char *p1; グローバル非初期化領域 
main() 

int b; stack 
char s[] = "abc" ;スタック 
char *p2; スタック 
char *p3 = "123456"; 123456 は定数領域にあり、p3 はスタックにあります。 
static int c = 0; グローバル (静的) 初期化領域 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 
10 バイトと 20 バイトの割り当て領域はヒープ領域にあります。 
strcpy(p1, "123456"); 123456 は定数領域に配置され、コンパイラはそれと p3 が指す "123456" を 1 つの場所に最適化することがあります。 
2. 


ヒープとスタックの理論的知識 
2.1 アプリケーション メソッド 
スタック: 
システムによって自動的に割り当てられます。たとえば、関数内でローカル変数 int b を宣言すると、システムはスタック ヒープ内の b 用のスペースを自動的に開きます 

プログラマーは自分でそれを適用し、c の malloc 関数 ( 
p1 など)でサイズを指定する必要があります。 = (char *)malloc(10);  C++ ではp2 = (char *) malloc(10); などの 
new 演算子を使用します が、p1 と p2 自体がスタック上にあることに注意してください。 2.2 アプリケーション後のシステム応答 スタック: スタックの残りのスペースが要求されたスペースよりも大きい限り、システムはプログラムにメモリを提供します。それ以外の場合は、スタック オーバーフローを示す例外が報告されます。 ヒープ: まず第一に, オペレーティング システムには空きメモリ アドレスを記録するリンク リストがあることを知っておく必要があります. システムがプログラムからアプリケーションを受け取ると, 






リンクされたリストは、要求されたスペースよりもスペースが大きい最初のヒープ ノードを見つけるためにトラバースされ、その後、そのノードは空きノードのリンクされたリストから削除され、ノードのスペースがプログラムに割り当てられます。 、ほとんどのシステムでは、コード内の削除ステートメントがこのメモリ空間を正しく解放できるように、このメモリ空間の最初のアドレスにこの割り当てのサイズが記録されます。さらに、見つかったヒープ ノードのサイズが要求されたサイズと正確に等しいとは限らないため、システムは自動的に冗長部分をフリー リストに戻します。 
2.3 アプリケーションのサイズ制限 
スタック: Windows では、スタックは下位アドレスに拡張されるデータ構造であり、連続したメモリ領域です。この文は、スタックのトップのアドレスとスタックの最大容量がシステムによって事前に決定されていることを意味します.WINDOWSでは、スタックのサイズは2Mです(1Mと言う人もいます、要するに定数で決まります)コンパイル時)、要求されたスペースがスタックの残りのスペースを超えると、オーバーフローが求められます。したがって、スタックから取得できるスペースが少なくなります。 
ヒープ: ヒープは、上位アドレスに展開するデータ構造であり、不連続なメモリ領域です。これは、システムがリンクされたリストを使用して空きメモリ アドレスを格納するためです。これは当然不連続であり、リンクされたリストの走査方向は下位アドレスから上位アドレスです。ヒープのサイズは、コンピューター システムで使用可能な仮想メモリによって制限されます。ヒープによって得られたスペースは、より柔軟で大きくなっていることがわかります。 
2.4 アプリケーション効率の比較: 
スタックはシステムによって自動的に割り当てられ、より高速です。しかし、プログラマーは制御不能です。 
ヒープは new によって割り当てられたメモリであり、一般的に遅く、メモリの断片化が発生しやすいですが、最も便利に使用できます.さらに、 
Windows では、VirtualAlloc を使用してヒープ上にないメモリを割り当てるのが最善の方法です.またはスタック上で使用するのが最も不便ですが、プロセスのアドレス空間に直接高速メモリを予約することです。しかし、速度も最も柔軟な 
2.5 ヒープとスタックのストレージ コンテンツ 
スタック: 関数が呼び出されると、最初にスタックにプッシュされるのは、メイン関数の次の命令 (関数呼び出しステートメントの次の実行ステートメント) のアドレスであり、次に関数のパラメーターです。 C コンパイラでは、パラメーターは右から左にスタックにプッシュされ、次に関数内のローカル変数にプッシュされます。静的変数はスタックにプッシュされないことに注意してください。 
この関数呼び出しが終了すると、ローカル変数が最初にスタックからポップアウトされ、次にパラメーターがポップアウトされ、最後にスタックの一番上のポインターが最初に格納されたアドレス (メイン関数の次の命令) を指します。プログラムはこの時点から引き続き実行されます。 
ヒープ: 通常、ヒープの先頭にヒープのサイズを格納するために 1 バイトが使用されます。ヒープ内の特定のコンテンツは、プログラマによって配置されます。 
2.6 アクセス効率の比較 

char s1[] = "aaaaaaaaaaaaaaa"; 
char *s2 = "bbbbbbbbbbbbbbbbbb"; 
aaaaaaaaaaaa は実行時に割り当て; 
bbbbbbbbbbb はコンパイル時に決定; 
ただし、その後のアクセスでは、スタック上の配列はへのポインタよりも高速です文字列 (ヒープなど)。 
例: 
#include 
void main() 

char a = 1; 
char c[] = "1234567890"; 
char *p = "1234567890"; 
a = c[1];  a
= p[1]; 
return; 

アセンブリ コード 
10: a = c[1]; 
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
0040106A 88 4D FC mov byte ptr [ebp-4],cl 
11: a = p[1]; 
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] ] 
00401070 8A 42 01 mov al,byte ptr [edx+1] 
00401073 88 45 FC mov byte ptr [ebp-4],al 
最初のタイプは、読み取り時に文字列内の要素をレジスタ cl に直接読み取ります。最初に edx を指し、次に edx に従って文字を読み取りますが、これは明らかに遅いです。 


2.7 まとめ: 
ヒープとスタックの違いは、次のメタファーで見ることができます: 
スタックの使用は、レストランに行って食事をするようなもので、注文 (アプリケーションを発行) して支払い、食べる (使用する) だけです。お腹いっぱいになったら立ち去る 野菜のカットや洗いなどの下ごしらえ、皿洗いや鍋掃除などの仕上げ作業に気を使う必要がなく、早いのがメリットですが、自由度は高いです。小さいです。 
ヒープを使うのは、好きな料理を自分で作るようなもので、手間はかかりますが、自分の好みに合わせて自由度が高いです。 

ヒープとスタックの違いは、主に 
オペレーティング システムのヒープとスタックに分けられます。前述のように、言うまでもありません。 
データ構造の観点からヒープとスタックもありますが、これらは異なる概念です。ここでのヒープは、実際には (ヒープの性質を満たす) 優先キューのデータ構造を指し、最初の要素が最も高い優先度を持ちます; スタックは、実際には先入れ先出しの性質を満たす数学的またはデータ構造です。ラストアウト。 
スタックとスタックは一緒に呼び出されますが、それらの間にはまだ大きな違いがあり、継続的な呼び出しは単に歴史的な理由によるものです。

おすすめ

転載: blog.csdn.net/fengqy1996/article/details/123902504