メモリを割り当てるときにサイズを指定する必要があるときに混乱しmalloc
ますが、その時点で必要なサイズがわからない場合があるため、膨大な量のメモリを割り当てることもあります (これはあまり聞こえません)おそらくすべてを使用するわけではないので賢明です)またはrealloc
初期バッファサイズが小さくなりすぎたときに使用します。この 2 つのオプションは有効ですか? 2番目のものは良さそうですが、ドキュメントによると、realloc
...may move the memory block to a new location
これは非常に悪い考え/扱いにくい状況のように聞こえます(たとえば、呼び出した瞬間に同じアドレスを指す複数のポインターがある場合、realloc
それらはすべて無効になります)私は初心者ですC を使用している場合、大量のメモリを占有するように成長する場合としない場合があるバッファがある状況を処理する方法を誰か説明してもらえますか?
2 に答える
その時点で必要なサイズがわからない場合は、大量のメモリを割り当てるか(おそらくすべてを使用することはないので、あまり賢明ではないように思われます)、またはreallocを使用する場合があります。初期バッファサイズが小さくなりすぎます。この2つのオプションは有効ですか?
原則としてそうです。実際には、最新のOSカーネルとデフォルトのシステム構成では、 mallocでいくら割り当てるかは問題ではありません。ご覧のとおり、mallocはメモリではなくアドレス空間を割り当てます。実際にメモリを消費しないように、必要なだけアドレス空間を割り当てることができます。もちろん、OSは値に対していくつかの健全性チェックを採用します。たとえば、2GiBメモリしか使用できないシステム(RAM +スワップ)では、3GiBを割り当てることはできません。通常の構成では、単一のチャンクに割り当て可能なアドレス空間の最大のチャンクは、使用可能なシステムメモリの50%です。
Only when you actually write something to it, the OS will reserve memory for it. So don't use calloc, because it initializes memory with, i.e. write something into it.
So if you don't know how much exactly you'll need, just malloc a big chunk of address space, for which you know, by the characteristics of the kind of data processed, that it will easily hold whatever you're expecting. Once you've got it in memory, you can use realloc to shrink the allocation. For all implemantations that matter realloc will never move data when shrinking an allocation.
注意すべきことの1つは、メモリのオーバーコミットメントです。4GiBRAMを搭載したシステムで5つのプロセスを実行し、各割り当ては1GiBですが、すぐには書き込みを行わないとします。OSは、このアドレススペースを提供します。つまり、メモリをオーバーコミットします(航空会社がフライトシートをオーバーコミットするのと同じように)。しばらくして、プロセスはそれに書き込みを開始します。ある時点で、システムのメモリが不足し、OSはそれに対して何かをしなければなりません。「呼吸」する余地が再びできるまで、プロセスの強制終了を開始します。
ただし、メモリのオーバーコミットをオフにすることはできます。高信頼性システムで強くお勧めします。
おっしゃる通りです。ほとんどの場合、これらは 2 つの選択肢です。少し抽象化することで、「複数のポインター」の問題を回避できます。直接返されたポインターを渡す代わりに、malloc
別のデータ構造に貼り付ける場合:
struct malloc_wrapper
{
void *p;
} wrapper;
wrapper.p = malloc(INITIAL_SIZE);
代わりにそのデータ構造へのポインターを渡します。p
いつでも変更でき、新しい構造へのポインターを共有する人は誰でもそれに応じて更新されます。
void *tmp = realloc(somepointertowrapper->p, NEW_SIZE);
/* check tmp to ensure it's not NULL. That indicates a failure
* to realloc and the original pointer passed into realloc
* remains valid.
*/
somepointertowrapper->p = tmp;