C言語 - メモリ管理

コンピュータ・システム、特に組み込みシステムでは、メモリリソースは非常に限られています。特に、ハードウェアリソースによって制限され、モバイルエンドの開発者は、それを作るために第一に考慮プログラミングにおける問題点は、効果的にメモリリソースを管理する方法です。本論文では、要約にC言語のメモリ管理を学習するプロセスで作られて、間違った場所ならば、希望の読者は、私を修正することを躊躇します。

まず、いくつかの基本的な概念

  下に簡単にレビューC言語のメモリ管理メカニズム、いくつかの基本的な概念を探索しながら、このような関数、変数、スコープ、ポインタとしてC言語、メモリ管理についての知識より、中:

1.変数:説明はありません。しかし、必要な変数のいくつかのタイプのどれを把握するには:

  • グローバル変数(外部変数):ブロック外部変数が現れる{}、それはグローバル変数です。
  • ローカル変数(自動変数):一般的には、{}ブロック内部変数は自動変数が自動表示の定義をも用いることができる定義されています。
  • 静的変数:変数は、キーワード静的で修飾され変更されていないプログラム実行中にメモリ位置を指します。コードブロック内の静的変数は、内部コードブロックによってアクセスすることができ、コードブロックの外部スタティック変数は、変数アクセスにこのファイルを定義することができます。

注:外部変数が変更、状況に応じて、両方の定義がステートメントとしても見ることができるように見ることができる;しかし変性のextern関数のみを定義することができるときに、何の曖昧さは存在しません。

2.スコープ:一般的には、関数スコープとファイルスコープ等がある広義変数の範囲を指します。私は、スコープが事の領域や範囲を指し、理解し、そのような水滴として、存在できることを超えて、唯一0-100摂氏の間に存在することができ、広く「水」を話すことは、存在しないことになり氷やガスへ。

3.機能:説明はありません。

注:C言語の関数は、デフォルトではグローバルである、あなたは、関数の静的関数を宣言するために、静的なキーワードを使用することができます(定義された関数はこの関数のみのファイルでアクセスすることができます)。

第二に、メモリの4つの分野

  コンピュータのメモリは、メモリ領域とQQのブラウザのシェアなど、お互いを訪問することができない、プログラムや手順の間のメモリが独立している管理するために分割され、それぞれ、交換の訪問ではありません。:メモリは、以下に示すように、通常は、メモリの4つの分野と呼ばれる、4つの主要な領域がある多くの領域に分割され、私たちが理解する必要があるアプリケーションがメモリを共有することができ、各プログラムの管理を分割されています

 

                                           

1.エリアコード

  実行可能コード(プログラムコード命令、定数文字列など)のすべてがコード領域にロードされるときに、オペレーティングシステムプログラムがメモリにロードされ、実行時にこのメモリは一定です。プログラムの実行中に、命令の束で満たされているパラレルコード領域は、変更することはできません。関数は、関数がメイン関数を含む、コード領域に配置されるように、また、コードの一部です。

  注:「INT = 0;」;および変数の「= 0」の定義は「INT;」文が「INT」に分割することができ、文は、プログラムのコンパイル時に実行されるコードではないと「= 0」というフレーズにコード領域、コードのみの面積を置きません。

2.静的エリア

  すべてのグローバル変数と静的変数の静的プログラム格納領域。

3.スタック領域

  スタック(スタック)は、高度なメモリ・アーキテクチャの後に出ている、すべての自動変数、関数パラメータがスタックに保存されている、このアクションは、コンパイラによって自動的に完了し、我々はプログラムを書くときに考慮する必要があります。プログラム実行中のスタック領域はいつでも変更することができます。自動変数は、その範囲を超えたとき、自動的にスタックから吐出されます。

  • 各スレッドは独自のスタックを持っています。
  • スタックオーバーフローが発生し越えスタックの最大サイズは、固定されています。
  • 変数がスコープ外になった後、スタック上のメモリを自動的に解放されます。

  話は安いです、あなたのコードを示しています。

コードをコピー

//実験1:メモリアドレスコード領域が観測され、静的領域、スタック領域

#include "STDAFX.H"
INT N- = 0;
ボイド試験(INT BをINT)
{
のprintf( "パラメータアドレスの形態では:%D \ Nフォームパラメータbはアドレス:%D \ n"、& A 、&​​B);
}
int型_tmain(int型ARGC、_TCHAR * ARGV [])
{
静的INT M = 0;
int型A = 0;
int型B = 0;
のprintf(「自動可変アドレス:%D \ nは自動変数Bのアドレスは:%D \ n "&、&B);
のprintf("グローバル変数nアドレス:%D \ nは静的変数mアドレス:%D \ n」、&N、&M);
試験( 、B);
のprintf( "_関数Tmainのアドレスである:Dの%"、_tmain&);
GETCHAR();
}

コードをコピー

  結果は以下の通りであります:

                                                                         

  分析結果:aとbが定義され、順番に割り当てられている自動変数、スタック領域に格納されているが、メモリアドレスが12の唯一の違いは、Bよりも大きいのアドレスは、スタックは後者のデータのうち、前進するのでことに留意すべきですストレージ構造、第一のストレージは、ストレージ、bの後、上記のように可視化(ノートアドレス番号順)を表しています。範囲外ならば、変数bは、変数が破壊される先行します。これは、最後には出すことが最初の最後を出すために最初にすること、箱に入れて服のようなくらいです。

コードをコピー
//実験2:スタック変数とスコープ
の#include「stdafx.hを」
戻り値は、ポインタ//関数であり、これはプログラムを実行することができますが、しかしのでこれは、合法的ではありません
//必要が非でこれを行うには静的キーワードが改変前のX変数がインクリメントされ、すなわち静的INT A = 0;
INT *のgetX() { int型のx = 10; リターン&X; } _tmainをINT(INTのARGC、_TCHAR * ARGV []) { int型* P =のgetX( ); * P = 20である; のprintf( "%のD"、P *); GETCHAR(); }
コードをコピー

  このコードは、構文エラーがない、だけでなく、望ましい結果を得るために:20。しかし、書き込みはそれほど問題がある:内部()関数のボディのgetXための理由()変数はint * p =のgetX Xスコープ、ここに一時的なスタック変数xのアドレスを取得するには、関数呼び出しのアドレスの終了後、のgetX()実際の作業は、このような行為を避けるべきか、死ぬ方法がわからないため、無効な、しかしバック* P = 20がまだアクセスして変更することが、結果はまた、間違っている可能性があります。あなたは覚えている、関数の戻り値により、スタック変数の復帰に対処することはできません!

  また、スタックは、通常K.で、素晴らしいことではないだろう 大スタック変数を直接プログラム内の関数の配列に格納されている場合、メモリはおそらくオーバーフローすることであり、プログラムは(第3の実験として)クラッシュさせるスタック領域がいっぱいになったとき、厳密には、(スタックオーバーフローと呼ばれるべきであるが、またスタックメモリへ可変圧力、これはスタックオーバーフローと呼ばれています)。

コードをコピー
第三の実験@:何スタックオーバーフローを参照
INT _tmain(int型ARGC、_TCHAR * ARGV []) { CHAR array_char [* 1024×1024×1024 = {0}; array_char [0] = 'A'; のprintf( " S%」、array_char); GETCHAR(); }
コードをコピー

方法は?遊びに杭との関係でこの時間。

4.ヒープ領域

  ヒープ(ヒープ)とスタックは、あるメモリ領域にプログラムが実行されても、任意の時点ではなく、高度なポストスタック順序アウトのように変更することができます。さらに重要なことは、ヒープが大きい容器であり、その容量は、スタックよりもはるかに大きい、上記実験によって引き起こされる3つのメモリのオーバーフローを解決することは困難です。一般的に、より複雑なデータ型はヒープ上にあります。しかし、C言語、アプリケーション内で、手動でコードによって行わために、ヒープメモリ空間の必要性を解放します。32ビットオペレーティングシステムのために、オペレーティングシステム1G自身の使用で最大管理4Gメモリ、及び残りはユーザプログラムに第3世代である、ユーザ・プログラムは、理論的には3Gのメモリ空間を使用することができます。ヒープメモリは、手動で言語の実行環境GC(例えばC#は.NET上で実行されているとして、ガベージコレクションを持っている)しない限り、(C / C ++)解放されなければなりません。どのようにメモリ使用量の山?

  次に、割り当てる外観と空きヒープメモリ:

mallocとfree

  バイト(バイト)で、ヒープメモリ指定したサイズに割り当てられたとのmalloc関数で、void *型の関数が返すポインタ;無料malloc関数によって割り当てられたヒープメモリの解放を担当します。mallocとfreeはペアで使用する必要があります以下の例を参照してください。

コードをコピー
@実験4:スタックオーバーフロー問題
の#include "STDAFX.H" の#include "STDLIB.H" の#include "string.hの" 空隙print_array(Pチャー*、チャーN-) { int型I = 0; のための(I = 0; I <N-; I ++) { のprintf( "P [%Dは] =%D \ N-" I、P [I]); } } _tmain(int型ARGC、_TCHAR * ARGV [])がINT { チャー* P =(CHAR *)はmalloc( * 1024×1024×1024); // アプリケーション・ヒープ・メモリー内 のmemset(P、 ''はsizeof(INT)* 10); //は、 メモリ初期化 I = 0 INTを、 (用0 = I; I <10; I ++) { P [I] = I + 65; } print_array(P、10); フリー(P); //解放ヒープメモリアプリケーション GETCHAR(); }
コードをコピー

次のような結果を操作します:

   プログラムは、この実験だけで3スタックオーバーフローの問題を解決するだろう、正常に実行することができます。ヒープは?理論的には、それはすべての領域を使用することができますどのように大きなメモリ空間の外に加えて、システムによって占められます。実際に、我々は通常、QQ、などのブラウザソフトウェアが、一般的なケースで使用するのに十分なよう開くなど、これよりも小さくします。それは第二の実験に来るとき、私たちはどのように行う関数のアドレス内で定義された変数に戻す必要がある場合は、スタック変数のアドレスは、関数の戻り値で返すことができないのですか?私たちは、これを行うことができます:

コードをコピー
@実験5:
の#include "STDAFX.H" の#include "STDLIB.H" INT *のgetX() { int型* P =(INT *)はmalloc(はsizeof(INT)); //ヒープ空間のアプリケーション
戻りP ; } _tmain INT(INTのARGC、_TCHAR * ARGVを[]) { int型* PP =のgetX(); * PP = 10; フリー(PP); }
コードをコピー

  このような書き込みは問題ありません、缶関数はヒープのアドレスを返しますが、我々は、自由空間を介してアプリケーション・ヒープ・メモリ機能のリリースであることを覚えておく必要があります"INT * P =(INT * )はmalloc(はsizeof(INT));" "静的int型A = 0"に正当です。静的なメモリ領域は、プログラムの全期間のために有効であるため実行されているが、フリー機能の後ろに使用することはできません!

  ヒープメモリ空間内のアプリケーションに対してものcallocとのreallocの機能、および使用は、malloc関数に類似しています。

 第三に、ケーススタディ

ケースワン

 パート、次のように:

  部及びコードの主な機能UpdateCounter、それは、コード領域に格納されます。

  デフォルトでは、それが静的な領域に格納され、変数のグローバル配列であります

  主な機能に「char * B = NULL」を規定する自動変数b(可変)領域をスタックに格納されるように

  その後、「B =(チャー*)のmalloc(1024 *はsizeof(CHAR));」メモリ空間のスタック部に印加されるので、そのヒープ領域におけるこの空間

ケースII

  以下の点に注意してください。

  • スタックは、下位アドレスの上位アドレスから増加します。
  • C言語では、関数のパラメータを描画すると、右から左である A1、C、Bの三つのパラメータUpdateCounterスタック順序の関数ので
  • C言語とパラメータ引数は値によって渡される間、 UpdateCounter関数パラメータ[1]、C、B及び静的領域A [1]中、C、Bが同じではありません

  実行は、スタック内のときに、アプリケーション "B =(CHAR *)はmalloc(1024 *はsizeof(CHAR))" に> - "チャー* B = NULL" は、ポインタ変数b、アドレス0xFFF8にBを規定空であります(そのメモリアドレス0x77a0080を仮定して)メモリの一部は、Bを与え、この時点で、Bは、アドレスが変化しないが、その値は0x77a0080、ヒープのアドレス空間へのこの値のポイント(スタック変数はヒープ領域の値を指すようになります次のように)、Bメモリプロセスの変更します:

                                      ---------->

第四に、メモリ管理を学習する目的

  メモリ管理は適切なタイミングで私たちの未来のメモリを管理する方法を知って学んでいます。そこで質問がありますか?ヒープとスタックは、ときにそれを使用する場合は?一般的に次の三つの原則に従います。

  • あなたが正確にどのくらいのメモリフットプリントのデータを知っている場合は、データの量は、より大きなヒープを使用してスタックと小さいです。
  • あなたはデータの量がわからない場合は、好ましくは、(例えば、いくつかの保険など)のヒープと、(それはより多くのメモリを取る場合があります)。
  • あなたが動的に配列を作成する必要がある場合は、ヒープを使用します。
コードをコピー
第六の実験@:動的に作成されたアレイ
_tmain INT(INTのARGC、_TCHAR * ARGV []) { int型I; scanfの( "%のD"、およびI); INT *アレイ=(INT *)はmalloc(はsizeof(INT)* I ); 他の操作のため//...//場合、動的に作成された配列 フリー(配列); }
コードをコピー

最後に、最後の 

  オペレーティングシステムのメモリ管理は、最小単位はバイトではなく、ときにメモリページ(32ビットオペレーティングシステムのメモリページ典型的には4K)。例えば、メモリの初期アプリケーション1Kは、メモリページを割り当てるオペレーティングシステムが4Kのメモリです。:4Kがあるため、妥協の選択肢である小さいメモリページ、少ないメモリが無駄になりますが、オペレーティングシステムのメモリスケジューリング;、より多くのメモリが無駄になるが、高いオペレーティングシステムのメモリスケジューリング効率、頻繁にメモリの割り当てと解放することなく、より大きなメモリページ非効率的で、頻繁に割り当て、空きメモリを必要とします組込みシステムメモリのメモリリソースは、そのメモリページが小さくなり、不足しているので、開発中の組込みで特別な注意が必要です。

おすすめ

転載: www.cnblogs.com/sea520/p/12618594.html