発行元 やまもとこう .
エディションノート
本書は C/C++ プログラマーが Linux で C/C++ プログラミングの応用練習をする際の副読本・実験ハンドアウトとして執筆しました。
前半で Linux カーネルや glibc のソースコードリーディングによってメモリーとファイル関連のシステムとライブラリーを浅く広く理解し、後半で C++ アロケーターを作っていきます。
※注1:文体は端的でカジュアルな表現を心がけたので、ブログ調にアレルギーのある方は読まないほうが良いでしょう。
システム環境
- Ubuntu 18.04 (Windows 10 WSLは不可)
- Linux カーネル 4.18.16 (UKUUでインストール)
- glibc 2.7
- GCC-8.2.0
- GDB-8.1.0
前提知識
Unix の基本コマンドの実用的知識と C/C++ でのコーディングの経験が 1 年ぐらいあると望ましいです。
対象となる読者
本書は Linux 環境 C/C++ で色々と試行錯誤をしながらプログラミングしたい方向けです。
必要な知識・スキル
- Unix の基本コマンドの実用的知識
- C言語/C++のプログラミング
- 拙著「C++プログラミング(C++11/14/17)」のGDB・ライブラリーの章
- 拙著「C/C++プログラマーが予備知識として学ぶIntel64/MIPS32アセンブリ言語プログラミング・コンピューターアーキテクチャー改訂第二版」のメモリーアーキテクチャの章
正誤表
Linux のファイルシステムの章の「 file (カーネル)」の項目内に「 kmalloc() / vmalloc() / alloc_pages() 等の関数で確保したメモリー領域」と途中で途切れた行がありますが、不要な文なので無視してください。
筆者が内容にデバイスドライバを含めるか悩んでいた痕跡ではありますが、時期尚早と判断すべきところを、迷ったまま本文に該当する行を残してしまいました。
時間の都合により初版ではデバイスドライバの説明は入れませんでしたが、簡単なハローワールドプログラムでも書いておけば、中途半端に文章が終わることは無かったので、次の版では大幅に加筆修正する予定です。
Linux で C/C++ の足固め: Linux の メモリー/ファイル/mmap、malloc、C++ アロケーター
序文
対象となる読者
前提知識
開発環境
Linux と POSIX C
echo コマンド
シェルの確認
/dev ディレクトリー
echo のリダイレクト
アペンド
リダイレクトのファイル記述子
ファイル記述子間のリダイレクト
exec (bash)
ファイル記述子を閉じる
読み書きファイル記述子
/proc ディレクトリー
/dev/shm ディレクトリー
Linux (POSIX) のファイル入出力
system 関数
lseek()
fopen / fread / fwrite / fclose 関数
Linux でメモリー割り当て
32 ビットプロセスのレイアウト
malloc (cstdlib)
malloc を strace で検証してみる
ASLR と共有オブジェクト
MALLOC(3) Linux プログラマーマニュアル
brk / sbrk (unistd.h)
gdb で sbrk() の解析
strace によって brk() / malloc() のコールをチェック
glibc から malloc() の基本構造を理解してみる
malloc() の内部実装
アリーナによるマルチスレッド対応
アリーナオブジェクト( main_arena / malloc_state )
ヒープのヘッダーオブジェクト( heap_info )
チャンク( malloc_chunk )
チャンクサイズ
malloc_par
top チャンク
ビン
未整理ビン / スモールビン / ラージビン
ビンのインデックスの計算
32 ビットアーキテクチャのビン
64 ビットアーキテクチャのビン
ビン・インデックスのまとめ
ビンのチャンク連結
ビンの初期化
未整理チャンク( Unsorted Chunk )のマクロ
トップチャンク( Top Chunk )のマクロ
Binmap のマクロ
tcache
malloc() フリーチャンクの挙動
malloc.c の内部マクロ
チャンクを取り扱えるマクロ
ファーストビンの解放
malloc.c の内部関数
malloc()
_int_malloc() 関数
free()
calloc()
realloc()
alloca() 関数
alloca() の使用法
posix_memalign() / aligned_alloc()
glibc-2.7 の内部実装
アラインメントの仕組み
アラインメントの最少サイズ
大きめのアラインメント
複数のアラインメントでの検証
std::launder ( C++17 )
std::aligned_storage ( C++11 )
std::align ( C++11 )
std::aligned_alloc ( C++17 )
Linux カーネルのメモリーとファイルシステム
Linux の仮想メモリーエリア・メモリー記述子
メモリー記述子( mm_struct )
仮想メモリー領域( vm_area_struct )
ページ記述子( struct page )
ページとブロック
バッファー ( buffer_head )
ブロック I/O ( bio )
ページのキャッシュ
スラブレイヤー・スラブアロケーター
ファイルとメモリーのマッピング (mmap)
ページとハードウェア
ページキャッシュ ( struct address_space )
Linux のファイルシステム
カーネルヘッダー ( /usr/src/ )
カーネルソースのアーカイブ
super_block (カーネル)
inode (カーネル)
dentry (カーネル)
file (カーネル)
stat 構造体
mmap
mmap の使い方
マルチタスクで使えると共有メモリーオブジェクト
fork()
fstat 関数を使ってファイルサイズを指定する場合
MAP_PRIVATE の Copy-On-Write
fork() で MAP_PRIVATE の Copy-On-Write を検証
MAP_ANONYMOUS
アノニマスマッピング
/dev/zero
(汎用ではない)カスタムアロケーターの設計
アロケーターに必要な最低限の関数・オーバーロード・テンプレート
std::allocator を使うだけのリファレンスアロケーター
std::allocator を模したカスタムアロケーター
スタック領域に割り当てるアロケーター
配列内のアドレスの走査
ヒープへのフォールバック付きスタックアロケーター
コードをシンプルにする(内部バッファーのアドレスかのチェック)
ヒープ領域のアドレスに割り当て
malloc を使ってヒープに割り当て
カスタムヒープアロケーター
static オブジェクトはヒープっぽい領域に割り当てられるはず?
アロケーターをスタティックメンバーにするとどうなるのか?
アロケーターをセレクターで切り替え
アロケータークラス内での複数の割り当て方針を切り替え
C++ カスタムアロケーターの STL サポート(実験)
C++ カスタムスタックアロケーターの用語の復習
STL コンテナのサポート ( new / delete )
STL サポートの適用対象
STL コンテナ側のメモリー割り当て要件
mmap() を使ったカスタムアロケーター
ユーザーによるオブジェクト管理を前提にするカスタムページアロケーター
カスタムアロケーターによるブロック管理
(おまけ)アロケーターのポリモーフィズム
メモリーリソースクラス
std::experimental::pmr::memory_resource ( C++17 )
memory_resource でアラインメントの実装(非実用的な実験です)
ポリモーフィックアロケーター
std::pmr::polymorphic_allocator ( C++17 )
std::experimental::pmr::vector コンテナ ( C++17 )
std::pmr::polymorphic_allocator の動作チェック
ポリモーフィックアロケーターの実装