値の値段
前回取り上げたSwiftに対する不満の1つとして、
密結合しているおかげで循環参照の解消などをプログラマが制御できるのですが、
密結合しているということは別の手法を導入したり、 メモリ管理そのものをSwiftで実装することが難しいということでもあります。
今回はメモリ管理とはいったい何なのか、
Swiftの型、CPUの型
Swiftには多彩なデータ型が標準装備されているうえ、
UInt8
、UInt16
、UInt32
、UInt64
。符号付き整数?Int8
からなるただの配列です。少なくとも、
図1は、

スタック(stack)と函数(function)
何百冊に及ぶ長編作品
図2が、UInt64
)

こんまりメソッド
ではスタックさえあればどんなプログラムも動かせるのでしょうか? 理論上はYesです。しかしスタックには大の苦手が1つあります。それは可変長のデータ。たとえば画像をロードしたいとして、
しかし起こり得る最大のメモリ使用量をあらかじめ確保しないともっとヤバイことになります。そう。バッファオーバーフロー
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char s0[8] = "ABCDEFG";
char s1[8] = "0123456";
printf("s0@%p was ・"%s・"・n", s0, s0);
printf("s1@%p was ・"%s・"・n", s1, s1);
char *p = s1;
strncat(p, "789abcde", 15);
printf("s0@%p is ・"%s・"・n", s0, s0);
printf("s1@%p is ・"%s・"・n", s1, s1);
return 0;
}
% cc -Wall bufof.c && ./a.out s0@0x7ffee8b96990 was "ABCDEFG" s1@0x7ffee8b96988 was "0123456" s0@0x7ffee8b96990 is "89abcde" s1@0x7ffee8b96988 is "0123456789abcde"
それでは、
ヒープ(heap)と可変長データ(data)
現代OSにおける、
つまりメモリ管理とはこの
ちなみにどちらがスタックでどちらがヒープかは、

mallocとfree
それでは具体的に各言語はヒープをどのように管理してきたのでしょうか? まずC言語での例を見てみましょう。C 言語自体はヒープをまったく管理しません。その代わりヒープを管理するための函数を標準装備しています。その名はmalloc
。これで問題はマロく収まるでしょうか?
#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);
}
}
これは何かというと、 おわかりいただけただろうか。チェックアウトしない限り部屋は空室にならないのだ、 では次にSwiftの例を。 メモリ返却は、 実はSwiftに限らず、 2022年8月18日発売malloc()
してどこにメモリが確保されたかを表示する簡単なプログラムです。ただし引数はもう1つあって、free()
されません。
% ./a.out 8 0
where = 0x1099c9000
where = 0x109aca000
where = 0x109bca000
where = 0x109cca000
where = 0x109dca000
where = 0x109eca000
where = 0x109fca000
where = 0x10a0ca000
% ./a.out 8 1
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
where = 0x108648000
malloc()
の戻り値を受けるポインタを上書きしているので、free()
し忘れるとその領域はスレッドが生きている間は二度と取り戻せない。これをメモリリーク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
ループを抜ける時点で自動でなされています。しかしどうやってそれをなしているかはプログラマからは見えません。プログラマから見えないということは、
free
本誌最新号をチェック!
Software Design 2022年9月号
B5判/
定価1,342円
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識
OSSソースコードリーディングのススメ
企業のシステムを支えるOSとエコシステムの全貌
今さら聞けないSSH
MySQLで学ぶ文字コード
新生