malloc/allocaの使い方(C言語)

プログラミング

配列だと固定長のメモリーしか確保できませんが、mallocを使うと可変長のメモリーが確保できますので、上手に使えばメモリーの節約ができ非常に便利です。しかし、メモリー開放は手動で行うことになるので注意が必要です。

mallocの使用例

#include <stdio.h>
#include <stdlib.h>

void main(void)
{
    char *a;

    a = malloc(100);
    
    free(a);

    return;
}

実際にこんなローカル変数で良いような使い方はしません。

確保/開放の処理が遠く離れていたり、確保/開放とread/writeするスレッドが違ったりしていることが多いです。

mallocしたポインタをlist管理したりする場合もあり、個々の処理はさほど複雑ではないのですが、処理が離れてしまう事が多いため非常にfree漏れがよく起きてしまいます。

ただ、別プロセスでは参照できないので、プロセス間でメモリ共有したいときはsocketとかpipeを使って都度通信を行ってください。使いたくなる気持ちはすごくわかりますが、プロセスをまたいたメモリ共有をしたいのであれば、きちっとプロセス間通信の設計してください。

allocaはfreeしてはだめ!

allocaはローカル変数のような可変長の配列のように使用できます。

allocもスレッド間でアドレスは共有できます。プロセス間はmallocと同じく共有出来ません。

関数や{}のようなスコープを抜けると自動で開放されます。ローカル変数と同じです。だから、関数の戻り値にallocaで取得したアドレスを戻すのは禁止です。戻した瞬間、開放されています。

allocaでは巨大なメモリ確保はできません。スタックオーバーフローが発生するため、スタック領域の空きを確認しながらサイズの上限を決めるべきです。

最後に、freeは不要というか、絶対にやってはいけません。

#include <stdio.h>
#include <alloca.h>
#include <stdlib.h>

void main(void)
{
    char *a;

    a = alloca(100);
    
    <span style="background-color: #ffff00" class="background-color"><span style="color: #ff0000" class="text-color">free(a);</span></span>//ダメ絶対!

    return;
}

これを実行するとダンプして落ちました。

$main
*** Error in `main': munmap_chunk(): invalid pointer: 0x00007ffc1a0a65c0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c91c)[0x7f9fce84a91c]
/lib64/libc.so.6(cfree+0x12c)[0x7f9fce85b0cc]
main[0x40051f]
/lib64/libc.so.6(__libc_start_main+0xea)[0x7f9fce7ee4da]
main[0x40042a]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:03 12190004                           /home/cg/root/6054590/main
00600000-00601000 r--p 00000000 08:03 12190004                           /home/cg/root/6054590/main
00601000-00602000 rw-p 00001000 08:03 12190004                           /home/cg/root/6054590/main
012e5000-01306000 rw-p 00000000 00:00 0                                  [heap]
7f9fce5b7000-7f9fce5cd000 r-xp 00000000 08:11 19138674                   /usr/lib64/libgcc_s-7-20170622.so.1
7f9fce5cd000-7f9fce7cc000 ---p 00016000 08:11 19138674                   /usr/lib64/libgcc_s-7-20170622.so.1
7f9fce7cc000-7f9fce7cd000 r--p 00015000 08:11 19138674                   /usr/lib64/libgcc_s-7-20170622.so.1
7f9fce7cd000-7f9fce7ce000 rw-p 00016000 08:11 19138674                   /usr/lib64/libgcc_s-7-20170622.so.1
7f9fce7ce000-7f9fce995000 r-xp 00000000 08:11 19138625                   /usr/lib64/libc-2.25.so
7f9fce995000-7f9fceb95000 ---p 001c7000 08:11 19138625                   /usr/lib64/libc-2.25.so
7f9fceb95000-7f9fceb99000 r--p 001c7000 08:11 19138625                   /usr/lib64/libc-2.25.so
7f9fceb99000-7f9fceb9b000 rw-p 001cb000 08:11 19138625                   /usr/lib64/libc-2.25.so
7f9fceb9b000-7f9fceb9f000 rw-p 00000000 00:00 0 
7f9fceb9f000-7f9fcebc6000 r-xp 00000000 08:11 19138600                   /usr/lib64/ld-2.25.so
7f9fcedab000-7f9fcedae000 rw-p 00000000 00:00 0 
7f9fcedc2000-7f9fcedc5000 rw-p 00000000 00:00 0 
7f9fcedc5000-7f9fcedc6000 r--p 00026000 08:11 19138600                   /usr/lib64/ld-2.25.so
7f9fcedc6000-7f9fcedc8000 rw-p 00027000 08:11 19138600                   /usr/lib64/ld-2.25.so
7ffc1a086000-7ffc1a0a7000 rw-p 00000000 00:00 0                          [stack]
7ffc1a1fd000-7ffc1a1ff000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
/usr/bin/timeout: the monitored command dumped core
sh: line 1: 120

だから、絶対にallocaはfreeしてはいけません。

まとめ

  • mallocはfreeを忘れてはいけない。
  • mallocを使用するのは複雑な実装のときになることが多いので設計をきっちりしてfree漏れが起きないようにしてください。
  • mallocやallcaで確保したアドレスはスレッド間で共有できますが、プロセス間では共有できません。
  • allocaは可変長の配列のように使用できる。
  • allocaはfreeを実行するとダンプしてしまうので絶対に禁止。
  • allocaはスコープを出ると自動で開放される。→関数の戻り値には使用できない

非常に便利で上手に使えるとメモリーの効率は良くなりますので配列を多く使う方は、ぜひmallocやallocaを使いこなしてほしいなと思います。

コメント

タイトルとURLをコピーしました