**コンパイラにおける静的割り当て**

2025/12/24 7:53

**コンパイラにおける静的割り当て**

RSS: https://news.ycombinator.com/rss

要約

Japanese Translation:

(combining missing points and tightening language):**

## Summary
TigerBeetle の「静的割り当て」設計―起動時にコマンドライン引数に基づいてすべてのメモリを確保し、再割り当てを行わない――は RAM 使用量を制限します。システムは 1 MiB 以下の有限なメッセージのみを処理し、データはディスクに保存されます。不安定なネットワークでは、処理できないメッセージを永続的にキューに保持する代わりに単純に破棄します。この構成型アプローチにより、複数の有限 I/O サブシステム(例:routing.zig)を追加オーバーヘッドなしで組み合わせることができます。

記事はコンパイラも同様の分割アーキテクチャを採用できると主張します。大きな不変「出力領域」を持ち、O(1) メモリで処理される小さなストリーム処理コアが存在する構成です。各コンパイルチャンクは厳密に有限(例:単一ソースファイルを約 4 MiB に制限し、実行時に上書き可能)になります。変更間で中間データを永続化するために、モデルは生ポインタの代わりにインデックスを使用することを提案します。

成功すれば、この静的割り当てスタイルはコンパイラコードを簡素化し、メモリ不足エラーを減らし、保守性を向上させる可能性があります。これによりコンパイラ開発者、大規模ビルドシステム、および広範なソフトウェアツールエコシステム全体が恩恵を受けます。著者はこの分離を実験し、静的割り当てがデータベースシステムにもたらしたのと同じ明瞭さをもたらすかどうかを検証する予定です。

本文

2025年12月23日

TigerBeetle は「静的割り当て」を有名にしています。ここで言う「静的」とは、組み込み開発で使われる固定配列のことではなく、起動後にはメモリを確保しないという弱い形態です。TigerBeetle のプロセスが使用するメモリ量は ELF バイナリにハードコードされているわけではなく、実行時に渡すコマンドライン引数によって決まります。しかし、割り当ては起動時に一度だけ行われ、その後は解放もありません。長時間稼働するイベントループは、メモリ確保をせずに円環的に回転し続けます。

私は何年もの間、この手法がコンパイラにも応用できるかどうか疑問に思っていました。無理だと考えていたのですが、本日このアイデアから実践可能な示唆を得ることができました。


静的割り当て

  • 基礎問題の物理学
    分散型データベースは、少なくとも TigerBeetle の場合、驚くほど単純な「物理法則」を持っています。

  • 入出力がメッセージである
    各メッセージはサイズ(1 MiB)が有限です。システムの実際のデータはディスク上に保存され、任意に大きくなる可能性があります。しかし、単一メッセージによって適用される差分は有限です。入力と出力がともに有限なら、余分なメモリを必要とするケースは実際にはかなり限定的になります。

  • 合成性
    静的割り当ては常に監視し、資源を手動で管理しているように見えるかもしれませんが、実際には驚くほど合成的です。入力と出力が有限であれば、非確保処理は容易です。二つのシステムを組み合わせても問題なく機能します ― 例えば

    routing.zig
    は良い例です。

  • 同時実行制限
    唯一の問題は、同時に到着できるメッセージ数に物理的な上限がないことです。明らかに任意の数のメッセージを同時に処理することは不可能です。信頼性の低いネットワーク上で分散システムを動作させる場合、必要な処理資源が利用できないときにはメッセージを破棄する方が安全です。

  • 単純さ
    直感に反して、確保しないほうが確保よりも単純です。もし実現可能ならば!


コンパイラへの応用

残念ながら、コンパイラでこれを実現するのは不可能に思えます。「最大プログラムは 100 万関数以下」と言い切ることもできますが、それはメモリを無駄にし、ユーザー体験を損ないます。Hard Mode Rust のような固定サイズアリーナは静的割り当てとは異なります:アリーナではサイズが明示されるため OOM が起こり得ますが、静的割り当てなら OOM はなく、必要なメモリ量を知ることは起動完了まで分かりません。

コンパイラの「問題サイズ」は固定されていません ― 入力(ソースコード)も出力(実行ファイル)も任意に大きくなる可能性があります。しかし、TigerBeetle でも同様です:データベースサイズは固定ではなく、RAM ではなくディスクに保存されています。TigerBeetle はディスク上で静的割り当てを行っておらず、実行時に ENOSPACE で失敗する可能性がありますが、動的ブロックアロケータを使って不要になったセクタを再利用し、できるだけそれを回避しています。

したがって、次のように言えるでしょう:コンパイラは任意に大きな入力を消費し、任意に大きな出力を生成しますが、それらは「静的メモリ割り当て」の対象外です。起動時に「出力アリーナ」を確保して、コンパイラの作業結果である不変データを格納します。その後、処理したチャンクごとにこの出力を蓄積していきます。各チャンクサイズは必ず有限です。コードベース全体の総量を制限することは非現実的ですが、単一ファイルを 4 MiB(実行時上書き可能)までに抑えることなら妥当です。このようにコンパイラを「ストリーム処理」問題として扱うと、入力も出力も任意の大きさであっても、フィルタプログラム自体は O(1) メモリで実行されるべきです。

この設定では、出力データに対してポインタよりもインデックスを使う方が自然になります。これにより、変更間でディスクへ永続化するのが容易になり、また「変更チャンク」を空間的(新しいファイル)だけでなく時間的(古いファイルの新バージョン)にも考えることが奨励されます。

実際に得られるメリットはまだ不明ですが、試してみる価値はあると思います。O(N) のコンパイラ出力と O(1) 中間処理成果物を厳密に分離することで、コンパイラのアーキテクチャが明確になり、データベースで見られるような単純化されたコードが得られるかもしれません。

同じ日のほかのニュース

一覧に戻る →

2025/12/30 6:46

USPS(米国郵便公社)が切手印日付システムの変更を発表しました。

## Japanese Translation: > **概要:** > USPSは最終規則(FR Doc. 2025‑20740)を発行し、国内郵便マニュアルに「セクション 608.11 —『切手印と郵便保有』」を追加しました。この規則では、切手印の定義が正式に示され、該当する印記がリストアップされています。切手印は印付け日でUSPSがその物件を保有していることを確認しますが、必ずしもアイテムの最初の受理日と同一ではありません。USPSは通常業務で全ての郵便に切手印を貼らないため、切手印が欠落していても、その物件が未処理だったとは限りません。機械による自動切手印は、施設内で最初に行われた自動処理操作の日付(「date of the first automated processing operation」)を表示し、投函日ではなく、地域輸送最適化(RTO)や路線ベースのサービス基準により受理日より遅くなることがあります。切手印は小売ユニットからの輸送後やカレンダー日がまたがる場合に付けられることが多いため、郵送日を示す信頼できる指標ではありません。同一日の切手印を確保するには、小売窓口で手動(ローカル)切手印を依頼できます。小売窓口で料金を支払うと「Postage Validation Imprint(PVI)」が付与され、受理日が記録されます。また、郵便証明書、登録メール、または認定メールは提示日を裏付ける領収書として機能します。この規則の影響は税務申告において重要です。IRC §7502 は、文書が期限までに物理的に届けられなかった場合に、提出の適時性を判断する際に切手印の日付を使用しています。

2025/12/30 1:07

**Zig における静的割り当て** Zig のコンパイル時メモリ管理を使えば、実行時ではなくコンパイル時にストレージを確保できます。データ構造のサイズが事前に分かっている場合やヒープ割り当てを避けたいときに便利です。 ### 重要概念 - **コンパイル時定数** `const` や `comptime` の値を使い、コンパイラがコンパイル中に評価できるサイズを記述します。 - **固定長配列** リテラルサイズで配列を宣言します。 ```zig const buf = [_]u8{0} ** 128; // 128 バイト、すべてゼロ初期化 ``` - **静的フィールドを持つ構造体** 固定長配列やその他コンパイル時に決まる型を含む構造体を定義します。 ### 例 ```zig const std = @import("std"); // 静的サイズのバッファを持つ構造体 pub const Message = struct { id: u32, payload: [256]u8, // 256 バイト、コンパイル時に確保 }; // 静的割り当てを使う関数 fn process(msg: *Message) void { // ヒープ割り当ては不要;msg はスタック上またはグローバルに存在 std.debug.print("ID: {d}\n", .{msg.id}); } pub fn main() !void { var msg = Message{ .id = 42, .payload = [_]u8{0} ** 256, // すべてのバイトをゼロで初期化 }; process(&msg); } ``` ### 利点 - **決定的なメモリ使用量** – サイズはコンパイル時に分かる - **実行時割り当てオーバーヘッドがゼロ** – ヒープアロケータ呼び出しなし - **安全性** – コンパイラが境界と寿命を検証できる ### 使うべき場面 - 固定長バッファ(例:ネットワークパケット、ファイルヘッダー) - 短時間しか存続しない小規模補助データ構造 - 性能や決定的な動作が重要な状況 --- コンパイル時定数・固定配列・構造体定義を活用することで、Zig は最小限のボイラープレートで最大の安全性を保ちつつメモリを静的に割り当てることができます。

## Japanese Translation: > **概要:** > このプロジェクトは、Zigで書かれた軽量Redis互換のキー/バリューサーバー「kv」を構築し、最小限のコマンドセットで本番環境に適した設計を目指しています。コアデザインでは起動時にすべてのメモリを確保することで、実行中にダイナミックヒープを使用せず、レイテンシスパイクやユース・アフター・フリー(use‑after‑free)バグを回避します。接続は`io_uring`で非同期に処理され、システムは3つのプール(Connection、受信バッファプール、送信バッファプール)を事前確保し、デフォルトでは約1000件までの同時接続数をサポートします。各接続は設定パラメータから派生した固定サイズの受信/送信バッファを使用します。 > コマンド解析はRedisのRESPプロトコルのサブセットに従い、Zigの`std.heap.FixedBufferAllocator`を用いてゼロコピーで解析し、各リクエスト後にアロケータをリセットします。バッファサイズは`list_length_max`と`val_size_max`に依存します。 > ストレージは未管理型の`StringHashMapUnmanaged(Value)`を使用し、初期化時に`ensureTotalCapacity`で容量を確保します。キーと値は共有`ByteArrayPool`に格納され、マップはポインタのみを保持します。削除操作では墓石(tombstone)が残り、墓石数が増えると再ハッシュが必要になる場合があります。 > 設定構造体(`Config`)は `connections_max`、`key_count`、`key_size_max`、`val_size_max`、`list_length_max` などのフィールドを公開し、派生アロケーションで接続ごとのバッファサイズを決定します。デフォルト設定(総計約748 MB、2048エントリ)では `val_size_max` または `list_length_max` を倍増すると、割り当て量が約2.8 GBに上昇する可能性があります。 > 今後の作業としては、カスタム静的コンテキストマップ実装の改善、より良いメモリ利用を実現する代替アロケータの探索、境界検査(fuzz)テストの追加による限界確認、および墓石再ハッシュ処理への対応が挙げられます。

2025/12/27 20:30

**フレームグラフ 対 ツリーマップ 対 サンバースト(2017)**

## Japanese Translation: **概要:** Flame グラフ(SVG)はディスク使用量を高レベルで明確に示します。たとえば、Linux 4.9‑rc5 では `drivers` ディレクトリが全容量の50%以上を占め、`drivers/net` サブディレクトリは約15%です。Tree マップ(macOS の GrandPerspective、Linux の Baobab)は非常に大きなファイルを素早く検出できますが、高レベルのラベルが欠けています;Baobab のツリー表示では各ディレクトリの横にミニバーグラフが表示されます。Sunburst(Baobab の極座標図)は視覚的に印象的ですが、角度で大きさを判断するため長さや面積よりも誤解しやすいです。他のツール―`ncdu` の ASCII バーと `du -hs * | sort -hr` ―はテキストベースで迅速なサマリーを提供しますが、同時に一階層のみ表示されます。 提案されたユーティリティは、これら三つの可視化(Flame グラフ(デフォルト)、Tree マップ、Sunburst)すべてを組み合わせるものです。Flame グラフは読みやすさ・印刷性・最小スペース使用量が優れているため、多数のサンプルファイルシステムでテストした後にデフォルトとして採用されます。このアプローチは、ディスク使用量を簡潔かつ印刷可能なスナップショットとして提供し、ユーザーや開発者がスペースを占有する項目をより効率的に検出できるよう支援します。アイデアは ACMQ の「The Flame Graph」記事と「A Tour through the Visualization Zoo」に引用された既存の研究に基づいています。 **反映された主なポイント:** flame グラフの高レベルビュー、Tree マップの大きなファイルを素早く検出できるがラベルが欠けている点、Sunburst の視覚的魅力とサイズ認識の問題、他ツールの制限、および提案ツールの三つのビュー(デフォルトは flame グラフ)と引用元への参照。