私はC++プログラミングに関する本をフォローしており、演習をフォローしています。ある演習では、メモリリークを生成するプログラムを作成するように求められます。このプログラムはそのようなリークを引き起こしますか?
int main()
{
int * pInt = new int;
*pInt = 20;
pInt = new int;
*pInt =50;
return 0;
}
私はC++プログラミングに関する本をフォローしており、演習をフォローしています。ある演習では、メモリリークを生成するプログラムを作成するように求められます。このプログラムはそのようなリークを引き起こしますか?
int main()
{
int * pInt = new int;
*pInt = 20;
pInt = new int;
*pInt =50;
return 0;
}
それが些細な例であることを考えるとdelete
、あなたとペアを組んでいないことnew
はリークです。この場合のリークを防ぐには、次のものが必要になります。
int * pInt = new int;
*pInt = 20;
delete pInt ;
pInt = new int;
*pInt =50;
delete pInt ;
メモリリークを検出するために使用する適切なツールはValgrindです。次のように、サンプルコードでツールを実行しました。
valgrind ./a.out
これは、それが生成した出力の一部です。
==14153== HEAP SUMMARY:
==14153== in use at exit: 8 bytes in 2 blocks
==14153== total heap usage: 2 allocs, 0 frees, 8 bytes allocated
==14153==
==14153== LEAK SUMMARY:
==14153== definitely lost: 8 bytes in 2 blocks
これは、実際にプログラムがメモリをリークしていることを確認します。
はい。リークを回避するには、を呼び出すたびにnew
、に一致する呼び出しを行う必要がありますdelete
。への呼び出しが2回new
あり、への呼び出しがないdelete
ため、リークが2回あります。
プログラムが終了すると、OSは割り当てられたすべてのメモリを解放することに注意してくださいnew
。したがって、メモリリークは、重要なプログラムの場合にのみ問題になります。
はい、これにより1つではなく、2つのメモリリークが発生します。割り当てられた両方int
のメモリリークが発生します。さらに、最初のアイテムは回復不能にリークされます。2回目に割り当てるとpInt
、new int
最初に割り当てられたアイテムは永久に失われます。
このプログラムはリークを引き起こしますか?
はい、そうなります。
One exercise asks me to create a program that produces a memory leak.
このプログラムはそのようなリークを引き起こしますか?
完全なエクササイズ、そしてあなたのコードはエクササイズへのより良い答えです!
ポインタとメモリリーク。これらは本当に開発者のデバッグ時間のほとんどを消費するアイテムです
メモリリークは本当に迷惑になる可能性があります。次のリストは、メモリリークが発生するいくつかのシナリオを示しています。
Reassignment, I'll use an example to explain reassignment.
char *memoryArea = malloc(10);
char *newArea = malloc(10);
これにより、以下の図4に示すメモリ位置に値が割り当てられます。
http://www.ibm.com/developerworks/aix/library/au-toughgame/fig4.gif 図4.メモリーの場所
memoryAreaとnewAreaにはそれぞれ10バイトが割り当てられており、それぞれの内容を図4に示します。誰かが以下に示すステートメントを実行した場合(ポインターの再割り当て)
memoryArea = newArea;
そうすれば、このモジュール開発の後の段階で確かに困難な時期にあなたを連れて行くでしょう。
上記のコードステートメントでは、開発者はmemoryAreaポインターをnewAreaポインターに割り当てています。その結果、下の図5に示すように、memoryAreaが以前に指していたメモリ位置が孤立します。この場所への参照がないため、解放できません。これにより、10バイトのメモリリークが発生します。
http://www.ibm.com/developerworks/aix/library/au-toughgame/fig5.gif 図5.メモリー・リーク
Before assigning the pointers, make sure memory locations are not becoming orphaned.
Freeing the parent block first
Suppose there is a pointer memoryArea pointing to a memory location of 10 bytes. The third byte of this memory location further points to some other dynamically allocated memory location of 10 bytes, as shown in Figure 6.
http://www.ibm.com/developerworks/aix/library/au-toughgame/fig6.gif 図6.動的に割り振られたメモリー
free(memoryArea)
** freeを呼び出すことによってmemoryAreaが解放されると、その結果、newAreaポインターも無効になります。newAreaが指していたメモリ位置は、その位置を指すポインタが残っていないため、解放できません。つまり、newAreaが指すメモリ位置が孤立し、メモリリークが発生します。
動的に割り当てられたメモリ位置へのポインタを含む構造化要素を解放するときは常に、最初に子メモリ位置(例ではnewArea)に移動し、そこから解放を開始して、親ノードに戻ります。ここでの正しい実装は次のようになります。free(memoryArea-> newArea); free(memoryArea); 戻り値の不適切な処理時々、一部の関数は動的に割り当てられたメモリへの参照を返します。このメモリ位置を追跡し、適切に処理するのは、呼び出し元の関数の責任になります。**
char *func ( )
{
return malloc(20); // make sure to memset this location to ‘\0’…
}
void callingFunc ( )
{
func ( ); // Problem lies here
}
In the example above, the call to the func() function inside the callingFunc() function is not handling the return address of the memory location. As a result, the 20 byte block allocated by the func() function is lost and results in a memory leak.
シャープリファレンス: http ://www.ibm.com/developerworks/aix/library/au-toughgame/
更新: あなたの興味は私に編集をさせてくれます
pとqにメモリを割り当てています。
p=new int [5];
/* ... */
q=new int;
ただし、配列はdelete []を使用して削除する必要があるため、無効な演算子を使用してpを解放するだけです。ある時点で、以下を使用してpとqの両方を解放する必要があります。
delete[] p;
delete q;
ポインタが他のポインタに割り当てられたバッファを指すようにしているため、どの削除演算子がどの新しい操作に対応するかを確認する必要がある場合があることに注意してください。
new []で割り当てられたバッファでdelete[]を使用し、newで割り当てられたバッファでdeleteを使用する必要があります。
ルール1:常に「malloc」の直後に「free」と書く</ p>
int *p = (int*) malloc ( sizeof(int) * n );
free (p);
ルール2:割り当てられたポインタを操作しないでください。コピーを使用してください!
int *p_allocated = (int*) malloc ( sizeof(int) * n );
int *p_copy = p_allocated;
// do your stuff with p_copy, not with p_allocated!
// e.g.:
while (n--) { *p_copy++ = n; }
...
free (p_allocated);
ルール3:倹約しないでください。より多くのメモリを使用します。
常に、必要以上のメモリを割り当てることから始めます。デバッグが終了したら、戻ってメモリ使用量を削減します。1000整数の長さの配列が必要な場合は、2000を割り当て、他のすべてが正常であることを確認した後でのみ、戻って1000に減らします。
ルール4:常に配列の長さを持ち運ぶ
配列がどこに行くにせよ、その長さに合わせて行く必要があります。良いトリックは、n + 1のサイズの配列を割り当て、nを0の場所に保存することです。
int *p_allocated = (int*) malloc ( sizeof(int) * (n+1) );
int *p_copy = p_allocated+1;
p_copy[-1] = n;
// do your stuff with p_copy, not with p_allocated!
free (p_allocated);
ルール5:一貫性を保つ。コメントを保存します
最も重要なことは、一貫性を保ち、自分がしていることを書き留めることです。コメントは時間の無駄だと思っているプログラマーの数にはいつも驚かされます。それらは必須です。コメントがないと、おそらく何をしたか思い出せないでしょう。コードを記述してから1年後にコードに戻り、そのインデックスの機能を思い出すために数え切れないほどの時間を費やしていると想像してみてください。それを書き留めるのに数秒を費やす方が良いです。
また、一貫していれば、頻繁に失敗することはありません。配列とポインタを渡すには、常に同じメカニズムを使用してください。物事のやり方を軽く変えないでください。私の以前のトリックを使用することにした場合は、どこでも使用してください。そうしないと、選択した参照の種類を忘れたために、存在しない場所を参照していることに気付く可能性があります。
参照:http://mousomer.wordpress.com/2010/11/03/simple-rules-to-avoid-memory-leaks-in-c/
はいといいえ。pIntが新しいintポインタで上書きされると、以前に割り当てられたメモリが失われますが、プログラムが戻ると、ほとんどの最新のオペレーティングシステムは、このメモリと、最後にpIntの割り当てを解除しないことによって失われたメモリをクリーンアップします。
つまり、本質的には、そうです、このようなものは2つのメモリリークを引き起こします。
これは、「new int」ステートメントを使用してスペースを割り当てますが、「delete」を使用してスペースを解放しないためです。