2011-08-16 22 views
20

Cのrealloc関数に関する簡単な質問 reallocを使用してポインタが指すメモリブロックを縮小すると、 "余分な"メモリが解放されますか?それとも、手動で何とか解放する必要がありますか?私はreallocを使用して割り当てられたメモリを縮小する

int *myPointer = malloc(100*sizeof(int)); 
myPointer = realloc(myPointer,50*sizeof(int)); 
free(myPointer); 

行う場合

は例えば、私は、メモリリークを持っていますか?

+1

厳密に言えば、あなたは 'realloc'の結果を記録しておらず、おそらく解放することができないので、メモリリークがあります。しかし、R ..の答えによると、実装の詳細については幸運かもしれません。 –

+1

あなたが正しいですよ。私はそれを修正しようとしました。今はどう? –

+6

新しいコードは、 'realloc'が失敗した場合でも元の割り当てをリークします。ほとんどの実装ではブロックを縮小することはできませんが、それは可能です。ブロックの拡大や縮小を問わずreallocを呼び出す正しい方法は 'void * tmp = realloc(myPointer、50 * sizeof(int));です。 if(!tmp){/ *何とかエラーを処理します。 myPointerはまだ古いブロックを指していますが、まだ割り当てられています* /} myPointer = tmp; '。 –

答えて

16

いいえ、メモリリークは発生しません。 reallocは、後でmalloc操作のために残りの部分を「利用可能」とマークするだけです。

でも、それでも後でfreemyPointerにする必要があります。脇に、reallocのサイズとして0を使用すると、一部の実装でfreeと同じ効果があります。 Steve JessopとR ..がコメントで言ったように、あなたはそれに頼るべきではありません。

+3

"reallocのサイズとして0を使用すると、空きと同じ効果が得られます。 - あなたの実装では真実かもしれませんが、保証されません。 'realloc'が0入力からヌルポインタを返し、errnoをENOMEMに設定しなかった場合、メモリは解放されました。しかし、mallocのように、reallocは使用可能な0のサイズの実際の割り当てを返そうとすることができます。実装は、どの(7.20.3/1)を記録する必要があります。 –

+2

Steveは正しいですし、実用的な結果は、サイズ0の 'realloc'を決して呼び出してはいけないということです。すべての可能な振る舞い、不適合な実装の存在、CとPOSIX皆さんは、何が適合しているのか、何が一致していないのかは、 'realloc(x、0)'に関連するものに頼ることを非常に悪い考えにしているようです。 –

+0

@Steve Jessop、R ..明確にしていただきありがとうございます:-)私はPOSIXを超えてチェックすることは決してありませんでした。 – cnicutar

11

ありメモリリークは間違いありませんが、サイズを小さくするreallocを呼び出すときに、少なくとも3つの事のうちのどれかが起こる可能性:

  1. 実装が新しい要求された長さと解放時に割り当てられたメモリブロックを分割最後に未使用部分。
  2. 実装は新しいサイズで新しい割り当てを行い、古い内容を新しい場所にコピーし、古い割り当て全体を解放します。
  3. 実装は何もしません。

オプション3はかなり悪い実装ですが、完全に合法です。後でfreeと呼ぶと、全体が解放されるため、「メモリリーク」はありません。

オプション1と2は、パフォーマンスを優先するか、メモリの断片化を回避するかによって、より優れています。私はほとんどの現実的な実装がオプション1を行うことに傾いていると信じています。

+0

割り当てられたメモリを減らす必要がある場合、オプション2の背後にある理由は何ですか?私はそれを理解することはできません。 – Jacob

+1

100バイトを割り当て、50バイトまでサイズを変更したいとします。最初の割り当ては100バイトの空き領域を要求し、オプション1は50バイトの空き領域を戻しますが、100バイト以上の領域は使用できなくなります。しかし、50バイトしかない別のフリーゾーンがあった場合、オプション2はその場所にデータを移動し、100バイトのゾーンを解放し、メモリの断片化を少なくします。 –

+0

最小の断片化を最適化することを目標としている場合は、割り当てを含むのに十分な大きさの小さな空き領域がすでに存在する場合にのみ、オプション2を使用することが理にかなっています。システムからより多くのメモリを取得しなければならない場合や、別の大きなフリーゾーンを分割する必要がある場合、断片化を悪化させるだけではなく、改善することができます。 –

3

あなたのコードを与えたところで、はい、それは漏れがあるかもしれません。 reallocのアイデアは、あなたのデータの新しい場所を返すことができるということです。あなたの質問でそれを行うのと同じように、reallocがあなたに送るポインタを失います。

int *myPointer2 = realloc(myPointer,50*sizeof(int)); 
assert(myPointer2); 
myPointer = myPointer2; 
+0

@R ..実際には私はそれほど確かではありませんでした。それはコメントの中で。あなたがそれを考えるなら、彼らは彼が実際に "余分な"記憶に何が起こるのか疑問に思うのは本当に彼の質問に尋ねました。 –

4

新しいコードは、再割り当てに失敗した場合でも元の割り当てをリークします。ほとんどの実装ではブロックを縮小することはできませんが、それは可能です。 reallocを呼び出す正しい方法は、ブロックを拡張するか縮小するかにかかわらず、void * tmp = realloc(myPointer、50 * sizeof(int))です。 if(!tmp){/ *何とかエラーを処理します。 myPointerはまだ古いブロックを指していますが、まだ割り当てられています* /} myPointer = tmp ;. - Steve Jessop 48分前

こんにちは、あなたのコメントに返信する方法を理解できませんでした。

myPointerのタイプにtmpをキャストする必要がありますか?この場合、私はまた

myPointer = (int*)tmp 

を記述する必要がない、この場合には、 (myPointer)I行う 空きメモリは、TMPが指す右、同様に解放されるのですか?したがって、必要はありません

+0

Reallocはまだリークします。これは正解です。少なくともWindows 7、64ビット(tdm-gcc64)では、 – dns

関連する問題