メモリ管理
(1)
- C++のスマートポインタや、Rustの所有権の考え方など、メモリ管理をできるだけ自動化しようという風潮があるように思います。
- プログラマにとって一番気楽なのはガーベージコレクションのある言語を使うことでしょう。オブジェクトを使わなくなれば自動で回収してくれるからです。しかしこれを実現するためにはポインタ変数のスキャンが必要になるので、処理の負荷としてはかなり大きなものになります。
- C++のスマートポインタやRustの所有権の考え方は、自動変数の寿命がスコープで消えることを利用して、そのタイミングで自動でメモリ解放をしようというものです。とてもよく考えられていると思います。
- 私はC言語でスマートポインタみたいなものを実現するにはどうしたらいいかを考えて、似たような仕組みを作ったのですが、出来上がってみると、これはまた別の応用が可能だなと気づいたのでそれを紹介します。
(2)
- まずC言語では自動変数の寿命が切れても、そのタイミングでfreeやオブジェクトのデストラクタを呼びだすような仕組みはありません。
- そこで、Cleanというクラス(の代わりの構造体と関数群)を作って、mallocするたびにCleanオブジェクトにfreeを呼びだすための情報を自動で登録していき、init関数は自動でdeinit関数を登録していき、スコープの末尾でプログラマが明示的にClean_outを呼び出して、登録された関数を呼び出してメモリ解放を実現します。
- このClean_outをやり忘れるようなことがあると解放忘れになってメモリリークということになりますが、個々のオブジェクトの管理をしなければいけないもとの状況よりは、Cleanオブジェクトだけ考えていればいい状態になったので、だいぶ楽です。
[例1]
MyObjA *a = myMalloc(sizeof (MyObjA), &clean); // こう書けば、もう free(a); をしなくていい.
MyObjA_init(a, &clean); // こう書けば、もう MyObjA_deinit(a); をしなくていい.
// まあしかし、私ならinitの処理内容を工夫して、NULLを渡したときには自動でmyMallocするように作るので、上記の2行は以下の1行で書ける.
MyObjA *a = MyObjA_init(0, &clean);