C++メモリ管理小結

4842 ワード

一.5つのメモリパーティション
C++では、メモリはスタック、スタック、フリーストレージ、グローバル/静的ストレージ、定数ストレージの5つの領域に分かれています.
スタックとは、コンパイラによって必要なときに割り当てられ、必要でないときに自動的に消去される変数の記憶領域です.中の変数は通常局所変数、関数パラメータなどです.
スタックは、newによって割り当てられたメモリブロックであり、彼らの解放コンパイラは管理されず、私たちのアプリケーションによって制御され、一般的に1つのnewはdeleteに対応しなければならない.プログラマーが解放されていない場合は、プログラムが終了するとオペレーティングシステムが自動的に回収されます.
フリーストレージエリアは、mallocなどで割り当てられたメモリブロックで、スタックとよく似ていますが、freeで自分の命を終わらせています.
グローバル/静的記憶領域では、グローバル変数と静的変数が同じメモリに割り当てられ、以前のC言語では、グローバル変数は初期化されたものと初期化されていないものに分けられ、C++にはこの区別はなく、同じメモリ領域を共有していました.
定数ストレージエリア、これは比較的特殊なストレージエリアで、彼らの中には定数が保存されていて、修正は許されません.
 
二.スタックとスタックの区別
スタックとスタックの明確な区別
bbsでは、スタックとスタックの区別の問題は、永遠の話題のようで、初心者はこれに対してよく混同されていることがわかるので、私は彼の最初のナイフを切ることにしました.
まず、例を挙げます.
void f() { int* p=new int[5]; }
この短い一言にはスタックとスタックが含まれています.newを見ると、まず、メモリのスタックを割り当てたと思います.ポインタpは?彼が割り当てたのはスタックメモリなので、スタックメモリにスタックメモリを指すポインタpが格納されているという意味です.プログラムでは、スタックに割り当てられたメモリのサイズを決定し、operator newを呼び出してメモリを割り当て、このメモリの最初のアドレスを返してスタックに入れます.VC 6の下のアセンブリコードは次のとおりです.
00401028 push 14h 0040102A call operator new (00401060) 0040102F add esp,4 00401032 mov dword ptr [ebp-8],eax 00401035 mov eax,dword ptr [ebp-8] 00401038 mov dword ptr [ebp-4],eax
ここでは、メモリを簡単に解放しないために、どのように解放すればいいのでしょうか.delete pですか?オーストラリア、間違っています.delete[]pのはずです.これはコンパイラに伝えるためです.私が削除したのは配列で、VC 6は対応するCookie情報に基づいてメモリを解放する仕事をします.
では、私たちは私たちのテーマに戻ります.スタックとスタックにはいったいどんな違いがありますか.
主な違いは以下の点です.
1、管理方式が違う;
2、空間の大きさが違う.
3、破片ができるかどうか.
4、成長方向が違う.
5、分配方式が違う;
6、分配効率が違う;
管理方式:スタックにとって、コンパイラによって自動的に管理され、手動で制御する必要はありません.スタックにとって、解放作業はプログラマーによって制御され、memory leakが発生しやすい.
空間サイズ:一般的に32ビットシステムでは、スタックメモリは4 Gの空間に達することができ、この観点からスタックメモリはほとんど制限されていない.しかし、スタックについては、一般的に一定の空間サイズがあります.例えば、VC 6の下では、デフォルトのスタック空間サイズは1 M(そうですが、はっきり覚えていません).もちろん、修正できます.
プロジェクトを開き、メニューを順に操作します.Project->Settings->Link、CategoryでOutputを選択し、Reserveでスタックの最大値とcommitを設定します.
注意:reserveの最小値は4 Byteです.commitは仮想メモリのページファイルに保存されており、スタックに大きな値を設定すると、メモリのオーバーヘッドと起動時間が増加する可能性があります.
フラグメントの問題:スタックにとって、頻繁なnew/deleteはメモリ空間の不連続をもたらし、大量のフラグメントをもたらし、プログラムの効率を低下させるに違いない.スタックにとって、この問題は存在しません.スタックは先進的な後出キューであるため、彼らはこのように対応しており、スタックの間からメモリブロックがポップアップすることは永遠に不可能です.彼がポップアップする前に、彼の上の後進的なスタックの内容がポップアップされ、詳細はデータ構造を参照することができます.ここでは、一つ一つ議論しません.
成長方向:スタックにとって、成長方向は上向き、すなわちメモリアドレスが増加する方向である.スタックの場合、その成長方向は下向きであり、メモリアドレスが減少する方向に成長します.
割り当て方法:スタックはすべて動的に割り当てられ、静的に割り当てられていないスタックです.スタックには、静的割当てと動的割当ての2つの割当て方式があります.静的割当ては、ローカル変数の割当てなど、コンパイラによって完了します.動的割り当てはalloca関数によって割り当てられますが、スタックの動的割り当てとスタックは異なり、彼の動的割り当てはコンパイラによって解放され、手動で実現する必要はありません.
分配効率:スタックは機械システムが提供するデータ構造であり、コンピュータは底層でスタックにサポートを提供する:専門のレジスタ格納スタックのアドレスを分配し、スタックを押し出すには専門の命令が実行され、これはスタックの効率が比較的高いことを決定した.スタックはC/C++関数ライブラリで提供され、そのメカニズムは複雑です.例えば、メモリを割り当てるために、ライブラリ関数は一定のアルゴリズム(具体的なアルゴリズムはデータ構造/オペレーティングシステムを参照できます)に従って、スタックメモリの中で利用可能な十分なサイズの空間を検索します.十分なサイズの空間がなければ(メモリの破片が多すぎるためかもしれません)、システム機能を呼び出してプログラムデータセグメントのメモリ領域を増やすことができ、十分なサイズのメモリに分けて返す機会があります.明らかに、スタックの効率はスタックよりずっと低い.
ここから、スタックはスタックに比べてnew/deleteの使用が大量になるため、メモリの破片が大量に発生しやすいことがわかります.専門的なシステムサポートがないため、効率が低い.ユーザ状態とコア状態の切り替えを引き起こす可能性があるため、メモリの申請は、より高価になります.したがって、スタックはプログラムの中で最も広く応用されており、関数の呼び出しでもスタックを利用して完了し、関数呼び出し中のパラメータ、戻りアドレス、EBP、ローカル変数はスタック方式で保存されている.だから、スタックではなくスタックを使うことをお勧めします.
スタックには多くのメリットがありますが、スタックに比べてそれほど柔軟ではないため、大量のメモリスペースを割り当てる場合があります.スタックを使うほうがいいです.
スタックでもスタックでも、オフショア現象の発生を防止しなければなりません(故意にオフショアさせない限り)、オフショアの結果はプログラムが崩壊するか、プログラムのスタック、スタック構造を破壊し、予想外の結果を生み出します.あなたのプログラムの実行中でも、上記の問題は発生していません.いつ崩壊するか分からないので、気をつけてください.その時debugはかなり困難でした:)
 
三.メモリわりあてほうしき
 
1.         :                  ,               。    ,static       。

グローバル領域(静的領域)(static)は、グローバル変数、静的データ、定数を格納します.プログラム終了後にシステム解放
文字定数領域定数文字列はここに置かれています.プログラムが終了するとシステムから解放されます.
2.スタック領域割当て:関連コードの実行時に作成され、実行終了時に自動的に解放されます.ローカル変数はここに格納されます.スタックメモリ割り当て演算はプロセッサの命令セットに組み込まれており、効率は高いが、容量は限られている.
3.      :      。 new/malloc   ,delete/free   。        ,  。         

スタック領域(stack)はコンパイラによって自動的に割り当てられて解放され、関数を実行するために割り当てられた局所変数、関数パラメータ、戻りデータ、戻りアドレスなどが格納される.その動作は、データ構造内のスタックに似ています.
スタック領域(heap)は一般にプログラマによって割り当てられて解放され、プログラマが解放されなければ、プログラム終了時にOSによって回収される可能性がある.割り当て方法はチェーンテーブルに似ています.
動的割り当てではメモリフラグメントが発生し、最終的に動的割り当てでは不要な時間のオーバーヘッドが浪費されます.
動的な割り当てに失敗しました.戻り値を確認したり、例外をキャプチャしたりする必要があります.これにより、追加のオーバーヘッドが発生します.
動的に作成されたオブジェクトは、複数回削除されたり、削除された後も使用され続けたりすることがあります.これにより、ランタイムエラーやプログラム消費メモリが発生します. 
int a = 0;//グローバル初期化領域char*p 1;//グローバル未初期化領域int main(){int b;//スタックchar s[]=/「abc/」//スタックchar*p 2;//スタックchar*p 3=/「123456/」;//123456//0は定数領域で、p 3はスタック上にある.static int c=0;//グローバル(静的)初期化領域p 1=new char[10];p 2=new char[20];//割り当てられた和バイトの領域はスタック領域にある.strcpy(p 1,/"123456/");//123456//0は定数領域に配置され、コンパイラはp 3が指す/「123456/」return 0と一致する可能性がある.