new / delete を“見える化”する！メモリ可視化ツール「Ichimi（いちみ）」入門

# new / delete を“見える化”する！メモリ可視化ツール「Ichimi（いちみ）」入門

![ichimi_top.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/131d1dc4-db95-4f7a-a2f6-2a420ed52fdb.png)


## 🔰 はじめに

C言語や C/C++ でよく登場する「ポインタ」「new」「delete」「malloc」「free」…
初心者が必ずつまずく最初の難関です。

メモリって何？どうなってるの？？ **必ずと言っていいほどハテナがたくさん** 飛び交います。😭
この最初の難関を乗り越えたとしても、 **実際にどんなメモリが確保されて、どこが解放されたのか**、なんとなくで済ませていませんか？

今回はそんな **メモリの動きを可視化して学べるツール「Ichimi（いちみ）」** を使って、new / delete の基本動作を **“見える化”** してみます！

---

## 💡 Ichimi（いちみ）とは？

「**Ichimi（いちみ）**」は、C/C++プログラムの **ヒープメモリ操作を CSV ログからヒートマップ表示するツール** です。

- 確保したメモリがどこに割り当てられたか  
- 解放した場所がちゃんと戻っているか  
- どの時点で断片化やリークしたか

などを、カラフルなヒートマップで直感的に理解できるツールです。

そんな特徴を持つ Ichimi（いちみ）を **"メモリの見える学習教材"** として役立ててみたいと思います。

> 💾 [Ichimi（いちみ）ダウンロード（BOOTH）](https://sappli.booth.pm/items/6997350) <br/>　📦 この記事のサンプルコードは、 **教材同梱 β 版** に含まれます。
> 📷 [Ichimi（いちみ）紹介動画](https://youtu.be/ScXYfNGIDO8)


## 🧪 今回試すコード

```cpp
// テストコード
void test()
{
	char* ptr1 = new char[ 100 ]; // 100 バイト確保
	char* ptr2 = new char[  50 ]; // 50 バイト確保
	delete[] ptr1; // 解放
	delete[] ptr2; // 解放
}
```

## 📄 CSV 出力の仕組み

Ichimi は **CSV ファイル形式のログを読み込んで表示** します。
CSV は下記のような形式です。

```
address,size,action,label
```

### CSV のフィールド仕様

| フィールド名 | 必須 | 内容 |
|-------------|------|-----|
| `address` | ✅ 必須 | メモリアドレスを16進数表記で入力します。`0x` は省略可能です。<br/>例：`10010000` |
| `size` | ⛔ malloc 時のみ必要 | メモリ確保時のサイズを **バイト単位** で入力します。`free` アクションの場合は空でOKです。 |
| `action` | ✅ 必須 | メモリ操作のタイプを指定します。`malloc`（確保）または `free`（解放）を記載します。 |
| `label` | ⭕ 任意 | ユニークな識別子として使用可能です。呼び出し元の関数名などを記入すると便利です。<br/> **半角65文字** を超えると表示が見切れます。 |

### CSV をプログラムから出力する手順

C/C++ プログラムで new / delete を利用してメモリの確保・解放を行い、 **実行時に CSV を出力** することで、メモリ時の状態を Ichimi（いちみ）で可視化できます。
```cpp
#include <stdio.h>
#include <stdlib.h>

// ログファイルポインタ
FILE*	logFile = nullptr;

// new[] をフック
void*	operator new[]( size_t size )
{
	void* ptr = _malloc_base( size );
	fprintf( logFile, "%p,%zu,malloc,from new[]\n", ptr, size );
	return ptr;
}

// delete[] をフック
void	operator delete[]( void* ptr ) noexcept
{
	fprintf( logFile, "%p,,free,from delete[]", ptr );
	_free_base( ptr );
}

// テストコード
void test()
{
	char* ptr1 = new char[ 100 ]; // 100 バイト確保
	char* ptr2 = new char[  50 ]; // 50 バイト確保
	delete[] ptr1; // 解放
	delete[] ptr2; // 解放
}

// エントリーポイント
int main()
{
	// ログファイルを開く
	fopen_s( &logFile, "Lesson01.csv", "w" );
	if( logFile == nullptr )
	{
		return 1;
	}

    // テスト
    test();

	// ログファイルを閉じる
	fclose( logFile );
    return 0;
}
```
すこし複雑になりましたが、 `test` 関数以外は、 **new[] と delete[] をフックして `Lesson01.csv` を出力** するコードになります。

:warning: 教材同梱 β 版に同様のコードが含まれますが、構成が異なります。<br/>　 IchimiLearning01.sln を VisualStudio で開いてご確認ください。


## 🔍 Ichimi で視覚化！

それでは実行したプログラムで、メモリがどのように確保・解放されるのかを見てみましょう。

1. bin/Ichimi.exe を実行して Ichimi を起動します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/4f6b7c37-5cae-4446-884b-094b4b610ad8.png)

1. Load CSV から `Lesson01.csv` を読み込みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/f251d1af-8b4e-4cf6-af7d-2919e66de98f.png)

1. ブラックサイズを 1B、履歴スライダーを一番左（0）にします。
すると、最初の new[] で確保された **100byte が赤く表示** されます。
💡 `1B にすると 1 ブロック（1 マス）が 1 バイトとして表示します。`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/6f6777f8-e2ad-4446-aa25-4a7f14b9e58b.png)

1. 赤いブロックをクリックすると、クリックしたブロック上に青枠が表示され、画面右にメモリ情報が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/fb7b99b4-366e-45e8-86ae-ca7973e55ab7.png)

1. さらに履歴スライダーを右に進めていくと、表示が順に変わっていきます。

このような感じで履歴スライダーを最初（左）から最後（右）まで順に進めると、次のように状態遷移が遷移していく様子が確認できます。
![ichimi_lesson01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/2a2281f6-9c7b-4c7d-a77a-99840f889bb4.gif)

細かく見ていくと、次のような感じでメモリの状態が遷移しています。

| 履歴 | Ichimi の表示 | test 関数の処理 | メモリに発生した事象 |
|------|-|-|-|
| 0    | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/d37dc53d-3a85-4658-8295-a18d01206dc2.png" width="100%"/> | char* ptr1 = new char[ 100 ] | 100 バイト確保 |
| 1    | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/e4d08f5b-767c-4113-96c8-231c7d01cd3b.png" width="100%"/> | char* ptr2 = new char[ 50 ] | 50 バイト確保 |
| 2    | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/b6c8e3f0-b29e-4d5c-8bed-dfec9bfe1530.png" width="100%"/> | delete[] ptr1; | 履歴 0 で確保した 100 バイトを解放 |
| 3    | <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4110475/47f3f6be-303d-4ad9-ab01-5ed71796707a.png" width="100%"/> | delete[] ptr1; | 履歴 1 で確保した 50 バイトを解放 |


## 🏁 まとめ

如何だったでしょう？
今回は基本的なメモリの確保・解放をしただけの簡単なものですが、 **メモリが見える** ことで理解が少しは深まったのではないでしょうか。

C/C++ 初心者にとってメモリをイメージして理解することはなかなか難しいものです。
今回の Ichimi（いちみ）の体験を通して、初心者 C/C++ プログラマーのスキルアップ⤴️のお役に立てたならウレしいです！😆


## 📚 さらに学びたい方へ

Ichimi を使った教材作成を予定しています！
- 断片化の視覚化
- メモリリークの視覚化
- 二重解放の動作確認

などなど