🔧

絶対にメモリリークが起きないメモリ管理ツールを作ってみた

commits2 min read

作ったきっかけ

私が通っている42tokyoのC言語の課題では、メモリリークが絶対に起きないようにプログラミングする必要があります。

もし、メモリリークが発生したら、その時点で課題は0点扱いになります😱

なので、いちいちfreeしなくても自動でfreeしてくれるツールを作ってみることにしました!

ソースコードは以下のリンクにあります。
ご自由に使ってください。バグや改善案などがありましたらコメントで書いてくれると嬉しいです!

https://github.com/kiri-42/libmem_mgt

追記

プログラムは無事完成したのですが、どうしてもグローバル変数が必要なのでグルーバル変数使用禁止の42の課題では使うことができないみたいです🥺

メモリを管理する方法

そもそも、どうやってメモリを管理するかについて簡単に解説していきます。

メモリの情報を管理する構造体配列を用意

まずは、メモリの情報を管理する構造体配列を用意します。
そして、メモリに関連する情報をメンバ変数として用意します。

今回は、メモリの開始アドレスとサイズ、確保した場所を記録したいのでこのような構造体になります。

typedef struct s_mem_info
{
	void			*ptr;  // 開始アドレス
	size_t			size;  // メモリサイズ
	const char		*file; // 確保した場所のファイル名
	unsigned int		line;  // 確保した場所の行数
	const char		*func; // 確保した場所の関数名
}	t_mem_info;

malloc・freeするたびに構造体配列を更新

mallocしたら構造体配列に要素を追加し、freeしたら構造体配列から要素を削除する関数をそれぞれ作成します。

malloc・freeを自作関数に置き換え

#defineを使ってmalloc・freeをそれぞれ先程自作した関数と置き換えます。

こうすることによりメモリを管理するプログラムが作成できます。

主な機能

主な機能としては以下の6つがあります。

  • mallocで確保したメモリの情報を記憶
  • プログラム終了時にメモリリークの検出&未解放のメモリを解放
  • プログラムの任意のタイミングで未解放のメモリの検出
  • プログラムの任意のタイミングで未解放のメモリを解放
  • 指定したサイズよりも多くメモリを確保した場合にエラー終了
  • メモリの確保上限を超えた場合にエラー終了

それぞれ簡単に解説していきます。

mallocで確保したメモリの情報を記憶

mallocで確保したメモリの以下の情報を記録します。

  • 開始アドレス
  • メモリサイズ
  • 確保した場所のファイル名
  • 確保した場所の行数
  • 確保した場所の関数名
  • 現在確保している合計のメモリサイズ
  • 現在確保しているメモリの数

プログラム終了時にメモリリークの検出&未解放のメモリを解放

exit関数をツールの中に含まれるmem_mgt_finish_check関数で#defineを使って置き換えているので、プログラムが終了する前にmem_mgt_finish_check関数が必ず呼び出されます。

この関数では、構造体配列に残ったメモリ情報をメモリリークとして表示し、全てfreeで解放します。

プログラムの任意のタイミングで未解放のメモリの検出

ソースコードの任意のタイミングでmem_mgt_check関数を呼び出すことにより、その時点での未解放のメモリの情報を表示します。

プログラムの任意のタイミングで未解放のメモリを解放

ソースコードの任意のタイミングでmem_mgt_free_all関数を呼び出すことにより、その時点での未解放のメモリを全て解放します。

指定したサイズよりも多くメモリを確保した場合にエラー終了

mem_mgt.hファイルのMAX_SIZEよりも確保したメモリのサイズが多くなった場合にエラーを表示してプログラムが終了します。

メモリの確保上限を超えた場合にエラー終了

mem_mgt.hファイルのMAX_NUMよりもメモリの確保数が多くなった場合にエラーを表示してプログラムが終了します。

使い方

  1. リポジトリをgit clone

    作業ディレクトリ内にリポジトリをcloneします。

    git clone https://github.com/kiri-42/libmem_mgt.git
    
  2. makeの実行

    cloneしたディレクトリに移動し、makeコマンドを実行します。

    cd libmem_mgt
    make
    
  3. ヘッダーファイルをインクルード

    管理したいプログラムにmem_mgt.hとreplace_mem_mgt.hをインクルードします。

    #include "libmem_mgt/mem_mgt.h"
    #include "libmem_mgt/replace_mem_mgt.h"
    
  4. mem_mgt_init()を呼び出し

    main関数の最初の行にmem_mgt_init();を追記します。

    特定の行でメモリ未開放領域を確認したいときは、その行にmem_mgt_check();を追記してください。

    特定の行でメモリ未開放領域をfreeしたいときは、その行にmem_mgt_free_all();を追記してください。

  5. コンパイルして実行

    2.で作成したlibmem_mgt.aを含めてコンパイルして実行すればメモリリークの情報を標準出力に検出してくれます。

注意事項

プログラムはexitで終了してください。

main関数のreturn終了やCtrl + Cには対応していません。

さいごに

説明が下手なのでよくわからなかったところが多々あったかと思います。
わからなかった箇所がありましたら、返信or記事を編集しますので、コメントを残してもらえると助かります。

GitHubで編集を提案

Discussion

ログインするとコメントできます