2009-04-10 10 views
2

は、次のCコードを考えてみましょう:malloc'edブロックを使用しないとどうなりますか?

int main(){ 
    int* c; 
    c = (int*)malloc(sizeof(int)); 
    c = 0xdeadbeef; 
    free(c); 
    return 0; 
} 

あなたが前にでmallocされたものではありませんこれは、Cを解放しようとしているので、これはセグメンテーションフォールトます。私の質問は、ブロックされたばかりのmallocだったのです。明らかにcはそれをもう指していないので、使用することはできませんが、それはまだ 'フリー'リストの一部と見なされていますか?これは明示的なメモリリークですか?

答えて

12

これはリークです。あなたのプログラムが終了すると、OSによって再利用されます。

+0

:あなたはこの出力を得るでしょう(libcの中で、()はmalloc()、reallocの()、...の機能を自由に交換し、独自に会計処理を実行することにより動作する)valgrindの中でこれを実行したい場合伝統的なUnixガベージコレクションスキーム:プログラムを実行し、終了時にメモリを再利用します。長い時間稼働している可能性が高いIDEやブラウザ、その他のプログラムではうまく機能しません。 –

1

すなわちコードは、メモリがまだメモリリークを引き起こして、割り当てられc = 7;

+0

free()はsegfaultするかもしれません。なぜなら、free()は迷惑ポインタを解消するからです。 – Michael

+0

Majd、あなたは技術的に正しいです(最高の一種)。しかし、ポインタを非常に無効なアドレスに変更し、逆参照しようとするのはむしろその全ポイントでした。 –

+0

あなたはc = 7から* c = 7に変更してもうまくいきません。話題は多少ありますが、彼は正しいです – Ben

10

*c = 7;に変更と仮定すると、セグメンテーションフォールトではないであろう。他の方法でそれをしたいですか?実際には、マシン/コンパイラが、割り当てたメモリを再利用する必要があることを知る方法はありません。これが適切な振る舞いではない場合、コードは確率的に機能します。コードを本当に信頼することはできません。

将来のある時点でそのメモリブロックをいつでも再ポイントすることができます。自動的に解放すると、あなたの下の敷物が引き出されます。

+0

C以外の言語については、あなたのためにそれを行うガベージコレクターと呼ばれるもの。 –

+0

はい、これはCです: – Anthony

0

malloc()によって返される値は、変換void* - >int*が自動であるため、キャストする必要はありません。

また、このような呼び出し書き換えることができます:あなたはcの種類を変更した場合

c = malloc(sizeof *c); 

だから今、あなたは全く配分を書き換える必要はありませんが。

[編集]

また、割り当てが成功したことを確認することをお勧めだろう(すなわちc != NULL)。

+0

4行目では、(int *)へのキャストが必要ですが、そうでなければ警告が表示されます。 –

+0

Cでは、(int *)か何かをmalloc()から離れることをお勧めします。それは必要ではなく、#が含まれていない可能性のあるエラーをカバーします。 –

1

malloc()の後、cはメモリアドレスを保持する変数です。この場合、cは、割り当てた最初のバイトのメモリアドレスの値を持ちます。

c = 7と言うときは、「cは現在メモリアドレス '7'」を指しています。この場合、メモリアドレス "7"はプロセスに割り当てられていないため、解放することはできません。理論的には、メモリアドレス "7"(または0xa73c930bfまたはそれに設定したもの)が実際にプロセスに割り当てられている可能性があります。その場合、free()は成功します。

ただし、cの値を変更すると、メモリは割り当てられたままになります。あなたのプロセスにはまだメモリとそのデータがあります。ポインタを失っただけです。あなたはその記憶がどこから始まるか分からない。

これは問題ありません。 Cでは、そのメモリアドレスを指す別の変数があるかもしれません。そのメモリアドレスを格納する "int *"ではなく、 "int"を持つことさえあります。 Cはあなたが特定のメモリアドレスを格納しているかどうかを追跡しようとはしません。そうすることは不可能な作業になるでしょう。追跡を続ける試みは、柔軟性のあるCポインターが失われる必要があるためです。

あなたの質問に答えてください:あなたはcの値を追跡する方法がないので、このプログラムはメモリリークを持っています。そしてそれによって、あなたのプログラムでは使用できないメモリがあり、リソースを無駄にしているということです。

ただし、プログラムが終了すると、プロセスに割り当てられているすべてのメモリが解放され、他のプログラムで使用できるようになります。

+0

アドレスをintに格納することは可能かもしれませんが、それは悪い考えです。 intとint *のサイズと表現が同じであるという保証はありません。 –

+0

あなたはfree()しようとすることができ、実装は実際にメモリを変更してfree()コードを実行するかもしれません。これはプログラムの残りの部分にとって重要であるかもしれないメモリのいくつかの塊ではうまく定義されていない何かをしたので、ほとんど常に悪いことです。 –

+0

ポインタを整数型変数に格納する場合は、intptr_tを使用します。 intptr_tは任意の型のポインタを格納するのに十分な大きさです。 – sigjuice

1

私に火を燃やさないでくださいが、私はあなたの質問のポイントを明確にしていません。明らかにあなたがやっていることは、あなたがやるべきことを言語が意図しているものと直接衝突していることです。 「消火器のノズルがガソリンタンクの穴に入ったからといって、私の車のガスタンクに消火器の液体を充填するとどうなるでしょうか?」と同じです。
私は馬鹿にしようとしているわけではありませんが、私はなぜこの特定の質問がなぜ明確ではないのですか?私はポインタの力を利用し、それらを間違って使用する方法がいくつあるのか不思議に思って、アプリケーションの失敗を招いています。 正しい方法を見つけ出すことができれば、あなたのコード*がやっていることを達成しようとしていることはありますか?または、あなたのポインタを追跡し、誤ってそれを追跡できなくなった場合にそのメモリを取り戻すのに役立つ内部メカニズムがあるのだろうかと疑問に思っていますか? (もしそうなら、その質問は上記で答えられた)。

1

これまでに割り当てられていなかったメモリを解放しようとしたため、この時点で取得するsegfaultは、オペレーティングシステムが許可していないメモリアドレスを参照しようとするためsegfaultが発生します(セグメンテーション違反の定義です)。

いくつかの実験では、あなたが出力としてこれを得るでしょう、あなたはvalgrindの中であなたのサンプルコードを実行しますと言う:

 
    ==6945== Invalid free()/delete/delete[] 
    ==6945== at 0x402265C: free (vg_replace_malloc.c:323) 
    ==6945== by 0x80483D5: main (bla.c:6) 
    ==6945== Address 0x7 is not stack'd, malloc'd or (recently) free'd 
    ==6945== 
    ==6945== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 1) 
    ==6945== malloc/free: in use at exit: 4 bytes in 1 blocks. 
    ==6945== malloc/free: 1 allocs, 1 frees, 4 bytes allocated. 

は、これは「PURが歌った」メモリリークです。今度は、解放しようとするポインタが割り当てたポインタの近くにあるようにコードを変更するとします(オペレーティングシステムはまだアクセスしていますが、オペレーティングシステムはバイト境界でメモリアクセスを許可しません)。私たちは、このようなコードを変更すると言う:

int main(){ 
    int* c; 
    c = (int*)malloc(sizeof(int)); 
    c++; 
    free(c); 
    return 0; 
} 

このアプリケーションを実行している場合、あなたが長い(カーネルによって放出された)セグメンテーションフォールトが、glibcのからの警告を取得しません(malloc関数の所有者を()とfree())

 
    [email protected]:/tmp$ ./a.out 
    *** glibc detected *** ./a.out: free(): invalid pointer: 0x0804a00c *** 
    ... followed by a trace 

だから、カーネルが、それはあなたに属している知っているのが、あなたにそれを配って覚えていないことができたglibcの一部のメモリを解放しようとしています。

 
    ==6955== Invalid free()/delete/delete[] 
    ==6955== at 0x402265C: free (vg_replace_malloc.c:323) 
    ==6955== by 0x80483D2: main (bla.c:5) 
    ==6955== Address 0x418a02c is 0 bytes after a block of size 4 alloc'd 
    ==6955== at 0x4022AB8: malloc (vg_replace_malloc.c:207) 
    ==6955== by 0x80483C0: main (bla.c:3) 
    ==6955== 
    ==6955== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 11 from 1) 
    ==6955== malloc/free: in use at exit: 4 bytes in 1 blocks. 
    ==6955== malloc/free: 1 allocs, 1 frees, 4 bytes allocated. 
+0

あなたのbashプロンプトにFSMを持つための+1。 –

関連する問題