たたいて学ぶfreeコマンド

## はじめに

本記事では、freeコマンドの出力結果をざっくり説明したあと、各項目について実際に値が変化する様子を見たいと思います。

freeコマンドの記事を参照する方の中には、Linuxに慣れていない方もいらっしゃると思うので、説明だけでなく、コマンドをたたきながら理解出来るようにすることが本記事の目的です。

また、本記事のコマンド実行は、Dockerでubuntuの環境を作成して行っています。

## `free`コマンドで確認できること

とりあえず、`free`コマンドの出力結果を見てみます。
1行目はヘッダーです。各列の数字が何を表すのかを示しているだけです。
2行目はメモリに関する各情報です。
3行目はスワップに関する各情報です。スワップはメモリが不足した際に、メモリの代わりとして使用されるストレージです。今回はスワップの説明はスコープ外とします。

```
root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      422476     4282336      423460     1384220     4972628
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

それでは、`free`コマンドでどのような情報が確認できるかを説明します。

- メモリの総量（total）
  - total = used + free + buff/cache という関係になっている
- 使用中メモリの総量（used）
  - カーネル、プロセス両方のメモリ使用量を含む
- キャッシュの解放をせずに、追加で利用可能なメモリの総量（free）
  - キャッシュにも使用されていない純粋な空き容量
- キャッシュ（バッファキャッシュ + ページキャッシュ）の総量（buff/cache）
  - カーネルの管理下だが、usedには含まれない
- 共有されているメモリの総量（shared）
- 追加で利用可能なメモリの総量（available）
  - freeに加えて解放可能なキャッシュのメモリ量も含む
  - メモリのfree < スワップのusedだとしても、スワップのused < メモリのavailableであれば、スワップの解放自体は可能

## メモリ使用量を増やして`free`コマンドの出力結果を確認する

配列を生成するシェルスクリプトを用いて、メモリ使用量が増えることを`free`コマンドで確認します。
シェルスクリプトは以下です。

```sh
#!/bin/bash

free

arr=()
for i in `seq 1 50000`
do
        arr+=$i;
done

echo -e "\n配列を生成しました\n"

free
```

上記のスクリプトを実行すると、以下の出力が得られます。
配列を生成することで、ざっくり5MiBくらいusedが増え、freeが減っていることが分かります。

```
root@6093f04a2a54:/home/free_tutorial# ./memory_used_experiment.sh 
               total        used        free      shared  buff/cache   available
Mem:         6089032      424300     4150100      423460     1514632     4970800
Swap:        2097148           0     2097148

配列を生成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      429696     4144696      423460     1514640     4965424
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

また、スクリプト実行後にfreeコマンドを実行すると、以下の結果が得られ、配列生成前のメモリ使用量と同程度に戻っていることが分かります。

```
root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      424252     4150108      423460     1514672     4970868
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

## ファイルを作成してキャッシュの増加を確認する

ファイル（1GiB）を新規作成し、それがページキャッシュされることを確認します。
（バッファキャッシュとページキャッシュの総量のため、厳密にはページキャッシュされているかは分からない、厳密に確認するにはsarコマンドを使います。）

ファイルを新規作成する前に、`free`コマンドを実行します。

```
root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      424652     4149604      423460     1514776     4970456
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

新規作成後、もう一度`free`コマンドを実行します。
1GiB程度のファイルが作成され、その分キャッシュ（buff/cache）が増えていることが分かります。
また、availableの値がほとんど変化していないことにも注目です。

```
root@6093f04a2a54:/home/free_tutorial# dd if=/dev/zero of=tmp_1g bs=1G count=1 
1+0 records in
1+0 records out
1073741824 bytes (1.1 GB, 1.0 GiB) copied, 1.21998 s, 880 MB/s

root@6093f04a2a54:/home/free_tutorial# ll tmp_1g 
-rw-r--r-- 1 root root 1073741824 Mar 19 10:52 tmp_1g

root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      427764     3067948      423460     2593320     4967372
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

削除すると、キャッシュも解放されます。

```
root@6093f04a2a54:/home/free_tutorial# rm -f tmp_1g

root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      426852     4146248      423460     1515932     4968284
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

## free（純粋な空きメモリ容量）以上にメモリを使用して、キャッシュの解放を確認する

前準備として、`dd`コマンドでキャッシュを増やして、空きメモリ量を減らしておきます。

```
root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      419304     4521748      423460     1147980     4967180
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# dd if=/dev/urandom of=tmp_4g bs=1024 count=$((1024**2*4))
4194304+0 records in
4194304+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 55.6795 s, 77.1 MB/s

root@6093f04a2a54:/home/free_tutorial# ll tmp_4g
-rw-r--r-- 1 root root 4294967296 Mar 19 11:38 tmp_4g

root@6093f04a2a54:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      430868      201224      423460     5456940     4955112
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

100MiBのファイルを作成し、`free`コマンドを実行することを繰り返すことで、free（純粋な空きメモリ容量）が不足しているとき、キャッシュが解放されることを確認します。
使用するシェルスクリプトは以下です。

```sh
#!/bin/bash

free

for i in `seq 1 5`
do
	dd if=/dev/urandom of=tmp_100m_$i bs=1024 count=$((1024*100))
	
	echo -e "\n100MiBのファイルを作成しました\n"

	free
done
```

上記のスクリプトを実行すると、以下の出力が得られます。
最初はfreeが200MiB程度であるため、100MiBのファイルを作成 → キャッシュという動きをします。
しかし、2回目以降はファイル作成前後で、ほとんどfreeの値が変化しません。
このことから、2回目以降はfreeが不足しているため、キャッシュを解放して、100MiBのファイルを作成 → キャッシュという動きをしていることがわかります。

```
root@6093f04a2a54:/home/free_tutorial# ./release_cache_experiment.sh 
               total        used        free      shared  buff/cache   available
Mem:         6089032      430956      201112      423460     5456964     4955024
Swap:        2097148           0     2097148
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.35139 s, 77.6 MB/s

100MiBのファイルを作成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      431100      113260      423460     5544672     4954880
Swap:        2097148           0     2097148
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.33974 s, 78.3 MB/s

100MiBのファイルを作成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      430684      118796      423460     5539552     4955252
Swap:        2097148           0     2097148
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.33965 s, 78.3 MB/s

100MiBのファイルを作成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      430248      112000      423460     5546784     4955804
Swap:        2097148           0     2097148
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.33563 s, 78.5 MB/s

100MiBのファイルを作成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      430704      117628      423460     5540700     4955168
Swap:        2097148           0     2097148
102400+0 records in
102400+0 records out
104857600 bytes (105 MB, 100 MiB) copied, 1.3298 s, 78.9 MB/s

100MiBのファイルを作成しました

               total        used        free      shared  buff/cache   available
Mem:         6089032      430572      114788      423460     5543672     4955296
Swap:        2097148           0     2097148

root@6093f04a2a54:/home/free_tutorial# 
```

## tmpfsを作成して、sharedの増加を確認する

共有メモリはプロセス間通信の際などに使われることが多いです。
しかし、今回はわざわざ `c` などでコーディングするのも面倒なので、`tmpfs`コマンドを使います。
tmpfsはメモリ上に作成される一時的なファイルシステムです。

`tmpfs`コマンドでメモリ上にファイルシステムを作成し、そこに10MiBのファイルを作成すると、sharedの値が10MiB程度増えることを確認できます。

```
root@2532b146d5d0:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      423820     4447700      423464     1217512     4963808
Swap:        2097148           0     2097148

root@2532b146d5d0:/home/free_tutorial# mkdir /tmp10 && chmod 777 /tmp10

root@2532b146d5d0:/home/free_tutorial# ll -d /tmp10
drwxrwxrwx 2 root root 4096 Mar 19 12:06 /tmp10/

root@2532b146d5d0:/home/free_tutorial# mount -t tmpfs tmpfs /tmp10 -osize=1G
            
root@2532b146d5d0:/home/free_tutorial# dd if=/dev/urandom of=/tmp10/tmp_10m bs=1024 count=$((1024*10))
10240+0 records in
10240+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.146004 s, 71.8 MB/s

root@2532b146d5d0:/home/free_tutorial# free
               total        used        free      shared  buff/cache   available
Mem:         6089032      423856     4437360      433704     1227816     4956548
Swap:        2097148           0     2097148

root@2532b146d5d0:/home/free_tutorial# 
```

## ついでに`free`コマンドのオプションもざっと確認する

`free`コマンドのオプションはそれほど難しくないので、ざっと実行しておいて、実際に使うときは`man`コマンドで確認すればすぐ使えるくらいの状態にしておく便利です！

```
root@2532b146d5d0:/home/free_tutorial# free -b  // バイト単位で出力
               total        used        free      shared  buff/cache   available
Mem:      6235168768   434221056  4543623168   444112896  1257324544  5077553152
Swap:     2147479552           0  2147479552

root@2532b146d5d0:/home/free_tutorial# free -k  // キロバイト単位で出力（デフォルト）
               total        used        free      shared  buff/cache   available
Mem:         6089032      424040     4437132      433704     1227860     4958560
Swap:        2097148           0     2097148

root@2532b146d5d0:/home/free_tutorial# free -m  // メガバイト単位で出力
               total        used        free      shared  buff/cache   available
Mem:            5946         414        4333         423        1199        4842
Swap:           2047           0        2047

root@2532b146d5d0:/home/free_tutorial# free -g  // ギガバイト単位で出力
               total        used        free      shared  buff/cache   available
Mem:               5           0           4           0           1           4
Swap:              1           0           1

root@2532b146d5d0:/home/free_tutorial# free -h  // いい感じの（人間が見やすい）単位で出力
               total        used        free      shared  buff/cache   available
Mem:           5.8Gi       413Mi       4.2Gi       423Mi       1.2Gi       4.7Gi
Swap:          2.0Gi          0B       2.0Gi

root@2532b146d5d0:/home/free_tutorial# free -s 1 -c 3  // 1秒おきに3回出力
               total        used        free      shared  buff/cache   available
Mem:         6089032      423724     4437384      433704     1227924     4958892
Swap:        2097148           0     2097148

               total        used        free      shared  buff/cache   available
Mem:         6089032      423724     4437384      433704     1227924     4958892
Swap:        2097148           0     2097148

               total        used        free      shared  buff/cache   available
Mem:         6089032      423732     4437376      433704     1227924     4958880
Swap:        2097148           0     2097148

root@2532b146d5d0:/home/free_tutorial# free -t  // メモリ + スワップの行を追加（4行目）
               total        used        free      shared  buff/cache   available
Mem:         6089032      423976     4437124      433704     1227932     4958640
Swap:        2097148           0     2097148
Total:       8186180      423976     6534272

root@2532b146d5d0:/home/free_tutorial# free -l  // メモリのうち、カーネルとプロセスの内訳を表示（buff/cacheがカーネルの管轄であることが確認できる）
               total        used        free      shared  buff/cache   available
Mem:         6089032      423968     4437132      433704     1227932     4958648
Low:         6089032     1651900     4437132
High:              0           0           0
Swap:        2097148           0     2097148

root@2532b146d5d0:/home/free_tutorial# 
```

## おわりに

簡単な実験を通して`free`コマンドを叩くことで、少しでも多くの人の理解度が上がれば嬉しいです。
統計情報出力系のコマンドをメインに、他のコマンドについてもこのような記事を書きたいと思ってます！