メモリ領域分割、メモリ割り当て、一定の記憶領域、ヒープ、スタック、フリー店、グローバル領域[C ++] [メモリ管理](RPM)

オリジナル:https://www.cnblogs.com/JCSU/articles/1051579.html

参考リンク:

 https://blog.csdn.net/weixin_40306859/article/details/90232204?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

 http://www.freesion.com/article/271421321/

 

 https://blog.csdn.net/One_L_Star/article/details/81901186

 

Aは、C、いくつかのメモリ領域に分割され
、自動的にコンパイラ放出によって割り当て- 1.スタック
2スタック-プログラマが解放しない場合、典型的には、プログラマ放出によって割り当てられたが、OSがプログラムの終了時に回収することができる
3.グローバル領域(静的領域)は、グローバル変数と静的変数は、一つに格納され、領域内のグローバルおよび静的変数を初期化し、初期化されていない変数は、他方に隣接するグローバル静的変数領域を初期化されていません。-プログラムのリリースの終了
に加えて4.定数を置くための特別な場所があります。-プログラム放出の終了
                                                                                                                                              
分布関数のmalloc、のcalloc、reallocのヒープ上に割り当てられ、他のメモリが得られると関数の本体内に定義された変数は、スタック上に通常あります。すべての機能は、他の文書へのexternことはできません、文書のin vitro効果的な表現で定義された静的変数に、グローバル領域(静的エリア)に格納されているところはどこでもすべての機能は、インビトロ定義された量に加え、静的な修飾子にグローバルであります関数定義の本体で使用される唯一のインビボで発現静的関数で有効です。さらに、「adgfdf」この文字列の機能は、一定の領域に格納されています。例えば:

INT A = 0 ; // グローバル初期化領域
のchar * P1; // グローバル初期化されていない領域
ボイドメイン()
{ 
    int型の B; // スタック
    チャー S [] = " ABC " ; // スタック
    のchar * P2; // スタック
    CHAR * P3 = " 123456 " ; // 一定領域内123456} {post.content、スタック上のP3 
    静的 INT C = 0 ; // 初期化グローバル(静的)ゾーン 
    P1 =(CHAR *)のmalloc10); //は、ヒープ領域の10バイトの領域に来る配分 
    P2 =(CHAR *)はmalloc20); // 20のバイトがヒープ領域領域になってきた割り当て 
    strcpyの(P1、" 123456 " );
     // 123456 {post.content}は定常領域で、コンパイラは、最適化に「123456」をポイントP3かもしれません 
}

II。でC ++は、メモリは、5つの領域に分割して、彼らは、ヒープ、スタック、無料の店、グローバル/静的記憶域と一定の格納領域です
、1スタック
されている必要とすることなく、必要なコンパイラによって割り当てられたものを、変数の明確な時に自動ストレージ領域。通常、ローカル変数、関数、その他のパラメータである変数。
2.ヒープ、新しいによって割り当てられたメモリのものをそのブロックは、新しい一般的には、削除に対応するであろう、私たちのアプリケーションによって制御するため、それらの放出コンパイラを気にしません。プログラマが解放されていない場合は、プログラムの最後に、オペレーティングシステムが自動的に回復します。
3.自由な店が、あること、ようにmalloc関数によって割り当てられ、これらのメモリブロックは、彼とヒープが非常に似ていますが、自分たちの生活を終了して自由です。
4.グローバル/静的な記憶領域を、グローバル変数と静的変数は同じメモリ、以前Cに割り当てられ、グローバル変数が初期化さに分割し、この区別を持っていないC ++、及びそれらの共通に初期化されていません同じメモリ領域を占有します。
5.定数格納領域、彼らは一定である店舗内の特殊な記憶領域である、(もちろん、あなたはまた、非合法的な手段で変更することができます)を変更することはできません

III。関係とヒープとスタックの違いについて話をするには
具体的には、現代のコンピュータ(シリアル実行機構)は、直接コード下にあるスタック内のデータ構造をサポートします。これは、データがオペランドスタックをスタック完了するために専用のマシン命令で、配置されているスタックのアドレスに専用レジスタ点に反映されます。この設計上の特徴は、直接、直接他のデータ構造をサポートしていないシステムでサポートされている点データタイプを浮動支持する効率、限定されたデータ、一般整数、ポインタ、等です。そのため、スタックのこの機能は、スタックはプログラムで非常に頻繁に使用することです。サブルーチンスタックへの呼び出しを直接終了しました。スタックにリターンアドレスでマシンの暗黙の呼び出し命令は、操作は、サブルーチンのアドレスと暗示ポップスタックとジャンプ動作からRET命令サブルーチンの戻りアドレスにジャンプします。C / C ++、なぜ関数が返す、の関数である自動変数スタックの直接の使用例である自動変数自動障害原因。

そして、別のスタック、ヒープデータ構造がないシステム(システムまたはマシンのオペレーティングシステムのいずれか)をサポートすることにより、ライブラリです。基本のmalloc / reallocを/ free関数は、ヒープデータ構造の内部セットを維持します。何が、その後、動的にプログラムデータセグメントのメモリサイズを増やすには、システムコールを使用しようとした場合、プログラムは、新しいメモリ空間を得るために、これらの機能を使用する場合、この機能を最初の試みは、ヒープメモリ空間内から利用できる見つけるために、メモリ空間を使用することはできませんヒープの内部に入るためにスペースの新しい割り当ては最初に行く、その後、呼び出し側に適切なフォームを返すために組織されました。プログラムは、割り当てられたメモリ空間を解放するときに、このメモリ空間は、スタック構造の内部に戻され、それが適切な処理であってもよい(例えば、自由空間のような、および他のより大きな自由空間に結合される)、より適切なアプリケーションへのメモリの割り当て。この複雑な分配機構が実際に等価であるメモリ割り当てプール(キャッシュ)、このメカニズムの使用は、以下のいくつかの理由があります
。1.システムコールは任意のサイズのメモリ割り当てをサポートしないかもしれません。いくつかのシステムは、システムがサポートするのみ固定サイズと(ページ割り当てによって)複数のメモリ要求を呼び出し、これは、小さなメモリ分類の多数の場合の無駄です。
2.アプリケーション・メモリ・システムコールは高価であってもよいです。システムコールは、ユーザーモードとカーネルモードの変換を伴うことがあります。
複雑なメモリ割り当ての大規模な数には管理メモリ割り当て解除動作3.原因メモリの断片化の可能性があります。

比較ヒープ及びスタック
スタックは、システム機能によって提供されるこれらの知見から、迅速かつ効率的な、欠点によって特徴付け制限されるが、データはフレキシブルではなく、スタックは、可撓性、広範囲のデータ適応面によって特徴付けられる、ライブラリ関数によって提供される機能であり、しかし、一定の効率が低下しています。スタックは、プロセス/スレッドのシステムデータ構造はユニークである。ヒープライブラリは一意必ずしも、内部データ構造です。お互いで動作するメモリの異なるヒープ割り当て。静的及び二種類の動的割り当ての空間分布をスタック。静的割り当ては、可変自動(オート)を割り当てるように、コンパイラが実行されています。動的な割り当ては、allocaの機能によって行われます。スタック(自動)を放出することなく動的割り当て、NO放出機能はありません。移植性のあるプログラムのために、動的に割り当てられたスタック操作が奨励されるべきでありません!ヒープ領域を割り当てるプログラムの終了すべてのデータ空間がバックシステムにリリースされますが、常に動的であるが、正確なアプリケーションメモリ/リリースメモリの試合は良いプログラムの重要な要素です。

    1.ゴミ問題:の面でヒープのために頻繁に新しい/削除、必然的に、メモリ空間の不連続性につながるので、手続きの効率を低下させる、破片の多くを引き起こしますスタックが懸念されるためにスタックはキューから進んでいるので、それは、この問題は発生しません、彼らは、その1彼がポップアップする前に、スタックの途中からメモリブロックポップアップを持っていることはありませんものにしています彼以上のスタック内容が後方に、詳細ができ>参照データ構造を排出された、ここで我々はそれを議論するつもりはありません。
    2.成長方向:ヒープが懸念されるため、成長方向、すなわちメモリ・アドレスが増加する方向に向かって、上向きであり、スタックのためにその成長方向の面には、下方に、メモリアドレスの成長の方向に縮小されます。
    3.割り当て方法:ヒープは、動的に割り当てられた静的ヒープを割り当てられていません。静的割り当てと動的割り当て:スタック割り当ての2種類があります。静的割り当ては、ローカル変数の割り当てとして、コンパイラに行われています。動的allocaの割り当て関数によって割り当てられますが、動的なスタック割り当てとヒープが異なっていて、彼の動的な割り当てがコンパイラによって解放され、私たちは手動で達成する必要はありません。
    4.割り当て効率:スタックがシステムによって提供される機械のデータ構造であり、スタックのための基礎となるサポートを提供するコンピュータ:特殊レジスタ・ストレージ割り当てられたアドレス・スタックは、スタックが決定実行される専用のプッシュ命令有するスタックの効率を比較的高いですスタックが提供されるC / C ++ライブラリであり、その機構が複雑で、例えば、メモリ・ライブラリ関数を割り当てるために特定のアルゴリズムに従う(特定のアルゴリズムがデータ構造/オペレーティング・システムを参照することができる)ヒープメモリが利用可能な検索十分な大きさのスペース(あまりにも多くの断片化されたメモリへおそらく)十分な大きさのスペースがない場合、メモリ空間プログラムのデータセグメントを高めるために、システムの機能を呼び出すことが可能であるので、メモリのサイズに割り当てられる十分な機会があると、リターン。スタックよりも明らかに、ヒープはるかに低い効率。

    ヒープとスタックの間に明確な区別
    BBS上で、ヒープとスタックを区別する問題は、永遠のテーマのようです、これは多くの場合、初心者のために混乱することを示しているので、私は彼の最初の手術を取ることにしました。
    まず、我々は例を与えます:

  

ボイドF()
{ 
    intは * P = 新しい INT [ 5 ]。
}

この単純な文は、新しいを見るために、ヒープとスタックが含まれている、我々は最初にすべての考えなければならない、我々は、ポインタpば、その後、ヒープメモリの一部を割り当てますか?:その意味することはこれですので、彼は、スタックメモリ割り当ての一部であるストアがスタックメモリにおけるポインタpヒープメモリへのポインタプログラムは次のように第1のスタック上に置かれ、このメモリの最初のアドレスに戻って、その後、ヒープ上に割り当てられたメモリのサイズを決定してからメモリを割り当てることがnew演算子を呼び出します、彼はVC6の下でコードをコンパイル:
    00401028プッシュ14H
    0040102Aコールオペレータ新しいです(00401060)
    0040102F追加ESP ,. 4
    00401032 MOV DWORD PTR [EBP-。8]、EAX
    00401035 MOV EAX、DWORD PTR [EBP-。8]
    00401038 MOV DWORD PTR [EBP-。4]、EAX
    ここでは、我々は簡単にするために、メモリを解放しません。 、その後、どのようにそれを解放するには?それは、p [削除ですか?オーストラリア、間違っている、あるべき[削除]はp型をコンパイラに伝えることです、私はアレイを削除、VC6は、対応するCookie情報の作業に応じて、メモリを解放することです。
    違いは何ですかヒープとスタック:まあ、私たちは私たちの話題に戻りますか?
    以下の主な相違点:
    1、別の管理;
    2、異なる大きさのスペース、
    3、異なる断片を生成することができます。
    4、異なる成長方向;
    分布を除いて5、
    6、異なる物流の効率化、
    管理:スタックが懸念されるため、コンパイラによって自動的に管理され、我々は手動で制御する必要はありませんが、ヒープの場合、リリースはプログラマの作業によって制御され、メモリリークが発生しやすいです。
    スペース:一般的な、32ビットシステムでは、4Gのヒープメモリ空間は、ビューヒープメモリのこの点から、達成することができるがほとんどない制限です。しかし、スタックが懸念しているため、スペースの一定量は、通常あり、例えば、以下のVC6では、デフォルトのスタック空間が1M(のような、覚えていない)です。:もちろん、我々は変更することができます
    プロジェクトを開く、その後、次のように操作]メニューをクリックしてください:プロジェクト- >設定- >リンク、カテゴリーでの選択出力を、その後、最大値を設定し、準備にスタックをコミットします。
注:予備4バイトの最小値を、コミットが大きなスタック内の仮想メモリページファイルに保持されるが、それは価値のより大きなセットを開きますようになります、メモリのオーバーヘッドを増加させると、起動時間を。
    ヒープとスタックの新しい多数/削除の使用に比べては、おそらくメモリの断片化の大規模な量を引き起こすために、特別な支援システムが効率的ではないがあるので、スイッチは、ユーザーモードとカーネルモードにつながる可能性があるため、アプリケーションのメモリは、コストがなり、より高価。そうであっても、関数呼び出しパラメータ、戻りアドレス、EBP、およびローカル変数は道のスタックを格納するために使用されている間に、完全にスタックを使用しても機能を呼び出し、それが最も広く、プログラムで使用されているスタック。したがって、我々はあなたがヒープではなくスタックを使用しようとお勧めします。

アクセスの効率のさらなる比較:
コード:

チャー S1 [] = " aaaaaaaaaaaaaaa " char * s2を= " bbbbbbbbbbbbbbbbb "

実行時の割り当てにaaaaaaaaaaa;
及びbbbbbbbbbbbはコンパイル時に決定される;
しかしながら、将来のアクセスに(例えば、スタック)高速ポインタによって指された文字列よりもスタック上のアレイ
例えば:

ボイドメイン()
{ 
    char型 A = 1 チャー C [] = " 1234567890 " char * p = " 1234567890 " ; 
    A = C [ 1 ]。
    A = P [ 1 ]。
    リターン; 
}

アセンブリ対応するコード
10:[1] A = C;
00401067 8A 4DフロリダMOVのCl、バイトPTR [EBP-0Fhの]。
0040106A 88 4D FC MOV PTRバイト[EBP- 4] Clで
11:A = P [1]。
図8(b)EC 55 MOV EDX 0040106D、DWORD PTR [EBP-14H]
00401070。8AアルMOV 42はPTRバイト[EDX + 1]、01
00401073 88 45 PTR FCバイトMOV [EBP-。4]、アル
第直読第二は、EDXに合わせて、中に最初の読み出しEDXポインタ値になりますが、読み取りレジスタCLの要素の文字列を入れて明らかに遅い、文字を読んで。
    ヒープやスタックは、我々は国境を越えた現象を防止する必要があるかどうか発生は結果がクロスボーダープログラムのクラッシュやプログラムのヒープ、スタック構造、実行されても、あなたのプログラムの過程で、予期しない結果を生成を破壊するのいずれかであるので、(あなたが意図的にクロスボーダーを作っている場合を除き)、上記の発生していません問題は、あなたはまだ注意する必要があり、あなたが出て崩壊するとき、あなたが知っていることはありません、コードの安定した安全を書くことは最も重要です

おすすめ

転載: www.cnblogs.com/lh03061238/p/12533225.html