フォロー、スター付きパブリックアカウント、エキサイティングなコンテンツへの直接アクセス
ID:チップホームダイ
著者:チェン・シーホイ
整理:シャオユ
オペレーティングシステムとして、またはHello Worldとして、またはアプリとして、または組み込みファームウェアとして使用できるかどうかにかかわらず、プログラムには多くの形式があります。本質的に、プログラムは関数コードとリソースのコレクションです。私たちのトピックは、プログラムのリソースであり、プログラムメモリの最初の要素です。
プログラムが人間の場合、スケルトンはプログラムの構造と比較でき、肉はコード、血液は記憶です。プログラムの実行プロセスでは、ほとんどの命令が実行され、ライトバック操作が行われ、ライトバックステージがメモリに対して実行されます。メモリには、プログラムの実行サイクル全体が付随していると言えるのです。 。では、メモリ内のガベージコレクションプログラムの「腎臓」とは何でしょうか。
int* a;
int b =2;
main()
{
static int c;
{
int d = 9;
char* e = malloc(10);
printf("d=%d\r\n",d);
}
}
これは非常に単純なC言語コードです。少し基本的な知識がある人は、このプログラムの各変数が占めるメモリ位置を知っています。
まず、グローバル変数と静的変数がデータセクションに配置されます(RWセクション。初期化されていない変数はZIセクションに配置され、プログラムの起動時にメモリがクリアされます)。例:a、b、c;
ローカル変数は、次のようなスタックスペースに配置されます。
同時に、ヒープに格納されたメモリのセクションにも適用されましたが、解放するコードでfree関数は使用されませんでした。
メモリの特性によると、a、b、cなどのデータセグメントの変数は、メモリに常駐し、ライフサイクルは永続的です。スタック内のローカル変数d、eの場合。それらのライフサイクルは「{}」内にのみあり、スタック操作、作成、および死のプッシュおよびポップ命令があります。
eがプログラム内の中括弧の外で死ぬと、ヒープに割り当てられたメモリがそのポインタを失い、メモリリークが発生します。単純なプログラムの場合、プログラムの背後にあるfree関数を使用してメモリを解放する限り、このような状況は比較的簡単に処理できます。
ただし、複雑なロジックプログラムがある場合、そのような動的に割り当てられたメモリは、管理に多くの労力を必要とします。これが、チュートリアルを作成するときにJavaなどの多くの高水準言語がC / C ++と比較するときに強調することが多い理由です。Javaにはポインターがなく、自動ガベージコレクションメカニズムがあり、安全でプログラムの堅牢性がより簡単に保証されます。 。(もちろん、C / C ++は堅牢なプログラムを作成することもできますが、それほど便利ではないものもあります)。プログラムがメモリの自動ガベージコレクションを自動的に実行できるようにするこのメカニズムは、プログラムの「腎臓」です。
では、なぜC / C ++は今まで自動ガベージコレクションをサポートしていないのでしょうか。自動ガベージコレクションメカニズムの原理から答えを見つけることができます。まず、自動ガベージコレクションの判定アルゴリズムについてお話しますが、一般的には次の2つがよく使われます:
A 、参照カウント。
名前が示すように、いわゆる参照カウント方法は、メモリ記述構造内のカウント変数を使用してカウントすることです。メモリブロックへのポインタまたは参照がある場合は常に、メモリブロックの記述構造内のカウンタがインクリメントされます。ポインターまたは参照が解放または変更されると、減少します。メモリブロックのカウントが0に減少すると、メモリブロックを解放してリサイクルできます。
参照カウント方法は、メモリ再利用可能性の判断を実現するための最も単純なアルゴリズムであると言えます。Appleの開発プラットフォームObject-CでサポートされているARCメカニズムは、このアルゴリズムを使用して自動回復メカニズムを実現する典型的な例です。この自動ガベージコレクションアルゴリズムの実装には、1つの依存関係と1つの欠点があります。コンパイラが自動的にカウントコードを挿入する必要性に依存します。
OCがxcodeプラットフォームでプログラムを開発するようにしたい場合、そのコンパイル環境は、retainやreleaseなどのステートメントを手動でカウントし、手動でカウントします。したがって、この自動ガベージコレクションの本質は、手動で行うべきことをコンパイラーに実行させることです。
Cが自動リサイクルのために同様の方法を実装する必要がある場合は、コンパイラーの前処理プロセスを変更し、メモリーのアプリケーションと解放のためにライブラリー関数の上にメモリー・モニター構造を維持して、メモリー・ブロックをカウントする必要があります。 。
同時に、参照カウント方法には非常に大きな欠点があります。つまり、循環参照はメモリリークを引き起こす可能性があります。次のコード:
fun()
{
A* a = [ A new];
A* a1 = a;
B* b = [B new];
B* b1 = b;
a->b = b;
b ->a = a;
}
関数が実行されると、aとbは相互に参照します。ただし、スタックとデータセグメントには、aとbのオブジェクトにアクセスできるポインターはありません。つまり、プログラムはこれらの2つのメモリへのアクセスを失いましたが、両方が互いにポイントしているため、メモリカウントをゼロに戻すことができません。そのため、解放できず、メモリリークが発生し、ゴミが発生します。
2.アクセシビリティ分析方法。
名前が示すように、到達可能性分析方法は、メモリプログラムが「到達」できるかどうかを分析することです。それは、プログラムがメモリへのアクセスを失ったかどうかを分析することです。プログラムの実行中、人体の血流が止まらないかのように、メモリは常に変化しています。しかし、どのような場合でも、プログラムがアクセスできる必要のあるメモリには、おおよそ2つのカテゴリがあります。
1.データセグメント、つまりグローバル変数と静的変数。
2.スタックスペース内の解放されていない変数は、現在スタック上にある動的ローカル変数です。
到達可能性分析メソッドは、ランタイム、つまりランタイム環境に依存する必要があります。これらのメソッドは、上記の2つの主要なタイプのメモリ内のポインター変数または参照を常に監視し、これらのポインターのポインターまたは参照を定期的にトラバースし、再帰的です。段階的に下に移動します。全体として、これらの2種類のメモリのポインタ変数と参照をエントリポイントとして使用して、グラフをトラバースします。トラバースできるメモリブロックに到達可能性のマークを付けることができる限り。
プログラムがガベージコレクションサイクルに入ると、プログラムは割り当てられているすべてのメモリを走査し、アクセスされたメモリブロックに到達可能マークがある場合はスキップします。到達可能マークがない場合は、解放してリサイクルできます。このようにして、参照カウントによって相互参照がカウントされるが到達できないが解放されないため、ゼロに戻らないという問題を回避することができます。下の図に示すように、青いメモリブロックがリサイクルされます。
ただし、到達可能性分析アルゴリズムは、ランタイム環境、つまりJavaなどの仮想マシンに依存しています。したがって、C / C ++などの言語は、この自動ガベージコレクション判定アルゴリズムをサポートできません。
そんなに多くを言いましたが、これらのプログラミング言語の診断の1つは次のとおりです:
OC:アップルは腎臓を変えましたが、腎臓は良くありませんでしたが、一般的には大丈夫でした。
java:腎臓はとても良いです。
C / C ++:腎臓がない場合は、腎臓透析を手伝ってくれるプログラマーが必要です。
C / C ++のような良い言語ですが、「腎臓」を与えて、より健康的な生活を送ることができますか?
答えはイエスです。
推奨読書:
嵌入式编程专辑Linux 学习专辑C/C++编程专辑
Qt进阶学习专辑关注微信公众号『技术让梦想更伟大』,后台回复“m”查看更多内容,回复“加群”加入技术交流群。
长按前往图中包含的公众号关注