書いて覚えるSwift入門

第48回 メモリ管理

この記事を読むのに必要な時間:およそ 3 分

ヒープ(heap)と可変長データ(data)

現代OSにおける,その答えがヒープ(heap⁠⁠。ここで思い出してください。スレッドにとってメモリは有限の配列であることを。有限の配列ということは,端が2つあるということです。スタックとは反対側の領域をインテリジェントな管理者に任せて,必要な量を伝えると空きメモリの場所=アドレスを教えてくれると。スタックに積むのはこのアドレスだけでいい。

つまりメモリ管理とはこの「インテリジェントな管理者」をどう実装するかという問題であり,よってメモリ管理≒ヒープ管理という等号が成り立つわけです。

ちなみにどちらがスタックでどちらがヒープかは,両端から真ん中に成長するのであればどちらでもかまわないはずですが,スタックは高アドレスから下り,ヒープは低アドレスから上るという順になっているOSがほとんどのようです図3⁠。

図3 ヒープと可変長データ

図3 ヒープと可変長データ

mallocとfree

それでは具体的に各言語はヒープをどのように管理してきたのでしょうか? まずC言語での例を見てみましょう。C 言語自体はヒープをまったく管理しません。その代わりヒープを管理するための函数を標準装備しています。その名はmalloc。これで問題はマロく収まるでしょうか?

Cプログラムのサンプル

#include <stdio.h>
#include <stdlib.h>
#define SIZE 1024*1024

int main(int argc, char *argv[]) {
    void *where;
    int n = 1 < argc ? atoi(argv[1]) : 0;
    int f = 2 < argc ? atoi(argv[2]) : 0;;
    while(n--) {
        where = malloc(SIZE);
        printf("where = %p・n", where);
        if (f) free(where);
    }
}

これは何かというと,1つめの引数で指定した回数だけmalloc()してどこにメモリが確保されたかを表示する簡単なプログラムです。ただし引数はもう1つあって,ここの指定がなかったり0だったりすると,メモリはfree()されません。

シェルでの実行例(その1)

% ./a.out 8 0
where = 0x1099c9000
where = 0x109aca000
where = 0x109bca000


where = 0x109cca000
where = 0x109dca000
where = 0x109eca000
where = 0x109fca000
where = 0x10a0ca000

シェルでの実行例(その2)

% ./a.out 8 1
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000

おわかりいただけただろうか。チェックアウトしない限り部屋は空室にならないのだ,と。しかも見てのとおりこの例ではmalloc()の戻り値を受けるポインタを上書きしているので,一度free()し忘れるとその領域はスレッドが生きている間は二度と取り戻せない。これをメモリリーク(memory leak)といい,忘れっぽい人間が間違いなく使いこなすには早過ぎる技術と言えるでしょう。

では次にSwiftの例を。

swiftでの例

let oneM = 1024*1024
let n = 8
for _ in 0..<n {
    var a = [Int8](repeating:0, count:oneM)
    a.withUnsafeBufferPointer {
        print($0)
    }
}
  • free()に相当する個所がないのにリークなし
  • メモリ確保だけでなく初期化も行っている。Cでいうとmalloc()はなくcalloc()だけがあるとも言える
  • 一度も上書きされていないことを検出して,変数varから定数letにせよと促してくる

メモリ返却は,forループを抜ける時点で自動でなされています。しかしどうやってそれをなしているかはプログラマからは見えません。プログラマから見えないということは,自動返却をどう実装するかは言語処理系に任されているということです図4⁠。

図4 メモリリークしないSwift

図4 メモリリークしないSwift

実はSwiftに限らず,free(フリー⁠⁠」なメモリ管理は多くの言語で採用されています。JavaScript,Perl,PHP,Python,Rubyといったスクリプト言語は,ほぼすべてそうですし,JavaやC++11以降のsmart pointerやGoやRustなど,オブジェクトコードにコンパイルするタイプの言語も増えてきました。ただしそれをどのように実現しているかは違いがあり,大きく分けて2つの流派があります。まとめて捨てる派とすぐ捨てる派。それぞれ一長一短があるのですが,紙幅オーバーフローが迫っているので続きは次回で。

Software Design

本誌最新号をチェック!
Software Design 2019年11月号

2019年10月18日発売
B5判/184ページ
定価(本体1,220円+税)

  • 第1特集
    ターミナルからクラウド管理自由自在
    Microsoft Azureで最新Webアプリ開発
    [Mac x bash]⁠Windows x WSL 2]⁠Visual Studio Code]⁠Windows Terminal]
  • 第2特集
    環境構築から使い方まで実践指導!
    脆弱性スキャナVuls/Trivy/Dockle
    OSSを公開したら人生が変わった3人の開発者
  • 短期集中連載
    Webエンジニアのための時短スマホアプリ開発
    【1】アプリ開発を継続するためにReact Native+Expoをお勧めするわけ

著者プロフィール

小飼弾(こがいだん)

1969年生まれ,東京都出身。元ライブドア取締役の肩書きよりも,最近はPokemon GOのガチトレーナーのほうが有名になりつつある……かもしれない永遠のエンジニアオヤジ。

活躍の場はIT業界だけでなく,サブカルからアカデミックまで多方面にわたり,ネットからの情報発信は気の向くまま毎日毎秒! https://twitter.com/dankogai,ニコニコチャンネルは,http://ch.nicovideo.jp/dankogai,blogはhttp://blog.livedoor.jp/dankogai/

当社刊行書籍は『小飼弾のアルファギークに逢ってきた』『小飼弾のコードなエッセイ』など。他にも著書多数。