スタック上で割り当てる(配分する)

2026/02/28 1:34

スタック上で割り当てる(配分する)

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

要約

Japanese Translation:

## 要約

Go の最近のコンパイラとランタイムの変更により、スライスの多くの割り当てがヒープからスタックへ移動し、割り当てオーバーヘッドと GC プレッシャーを低減しています。スタック上の割り当ては安価で GC なし、キャッシュフレンドリーです。

プログラム起動時に、小さなスライスに対する繰り返し `append` 操作が頻繁にヒープ割り当てを引き起こしていました。Go 1.24 以降では、容量固定の `make` がその背後配列をスタック上に割り当てることができます。Go 1.25 では、`make` 用に自動的な 32 バイトの小さなスタックバッファが追加され、要求された容量が極めて小さい場合にはヒープ割り当てを排除します。Go 1.26 はこの最適化を `append` にまで拡張し、コンパイラは最初の数回の `append` で投機的に小さなスタックバッファを使用し、必要に応じてヒープへフォールバックします。

スライスがエスケープ(例:関数から返される)すると、コンパイラは単一の `runtime.move2heap` 呼び出しを挿入し、スタック上で割り当てられたスライスをヒープへ移動させます。これにより不要なコピーが回避されます。その結果、Go 1.26 はエスケープするスライスについて、必要なサイズのヒープ割り当てを最大 1 回だけ(またはすべての作業が小さなスタックバッファ内に収まる場合は全く無し)生成します。

良い推定で事前に確保しておくことは、サイズが事前に分かっている場合には依然として有効ですが、多くの一般的パターンは自動的に処理されます。最適化によって回帰が発生した場合は、`-gcflags=all=-d=variablemakehash=n` で無効にできます。

これらの変更は GC ポーズを低減し、多数の短命スライスを生成するサービス(マイクロサービス、高スループット API、リアルタイムシステムなど)のレイテンシを向上させます。手動チューニングは不要です。今後のリリースでは最適化がさらに洗練されたり、追加フラグで挙動を微調整できるようになる可能性があります。

(元文に沿って欠落点を補足した場合)

  • 「Go 1.26 が
    make
    用に 32 バイトの小さなスタックバッファを追加した後」に、Go 1.24 の可変サイズスライスに対するヒープ割り当てルールと、エスケープ時に単一の
    runtime.move2heap
    呼び出しが行われることを説明する文を追加します。
  • -gcflags
    フラグで最適化を無効にできる旨の簡潔な注記を付け足します。

主メッセージの明確さと表現

改訂された要約は「スライス割り当てをスタックへ移動する」という主要アイデアを明確に保ち、あいまいな参照を排除しつつすべての重要技術詳細を網羅しています。

本文

Goプログラムを高速化する手段は常に探求されています。最近の2つのリリースでは、特に「ヒープ割り当て」による遅延を緩和することに注力しました。Goがヒープからメモリを確保するとき、その割り当てを満たすためにかなりのコード量が実行されます。また、ヒープ割り当てはガベージコレクタへの負荷も増大させます。Green Tea など最近の改善策にもかかわらず、ガベージコレクタは依然として相当なオーバーヘッドを抱えています。

そこで私たちは、ヒープではなくスタックでより多く割り当てる方法に取り組んでいます。スタック割り当ては実行がかなり安価(場合によっては完全に無料)ですし、ガベージコレクタへの負荷も発生しません。スタック割り当てなら、スタックフレームとともに自動的に解放されるため、再利用も容易でキャッシュ親和性が高くなります。


定数サイズのスライスをスタックへ

タスクを処理するためのスライスを作成するとします。

func process(c chan task) {
    var tasks []task
    for t := range c {
        tasks = append(tasks, t)
    }
    processAll(tasks)
}

最初のループでは

tasks
のバックアップストアが存在しないため、
append
は 1 要素分の領域を確保します。次に要素を追加するときは既存のストアが満杯になるので、サイズ 2 の新しいバックアップストアが割り当てられ古いものが捨てられます。3 回目でサイズ 4、4 回目では再利用、5 回目でサイズ 8…と、容量を倍増させながら最終的にはほとんどの
append
が追加割り当てを避けるようになります。しかしスライスが小さい「スタートアップ」フェーズでは割り当て回数が多くなるためオーバーヘッドが大きいです。

このコードがホットパートであれば、スライスを大きめに初期化するのは自然な最適化です。

func process2(c chan task) {
    tasks := make([]task, 0, 10) // おそらく最大で10個
    for t := range c {
        tasks = append(tasks, t)
    }
    processAll(tasks)
}

この最適化は決して誤りではありません。推測が小さすぎても割り当てが発生し、大きすぎればメモリを無駄にします。しかし、推測が合っていれば 1 回の

make
だけで済みます。驚くべきことに、チャネル内に10個しかない場合、このコードは割り当て数が 0 にまで減ります。コンパイラは正確なサイズ(10 個分)を知っているため、バックアップストアをスタック上に配置します。これは
processAll
内でヒープへ逃げないことに依存しています。


可変サイズスライスのスタック割り当て

固定長推測はやや硬直です。推定長を渡すようにすると:

func process3(c chan task, lengthGuess int) {
    tasks := make([]task, 0, lengthGuess)
    for t := range c {
        tasks = append(tasks, t)
    }
    processAll(tasks)
}

Go 1.24 では非定数サイズのバックアップストアはスタックに割り当てられず、ヒープへ落ちます。結果として「0 割り当て」から「1 割り当て」に変わりますが、それでも

append
が行う中間割り当てを減らせます。

Go 1.25 で変更がありました:コンパイラは特定のスライス割り当てサイトに対して、サイズが小さければ現在 32 バイト のスタックバックアップストアを自動的に確保します。要求されたサイズがその範囲内ならスタック上で完結し、それ以上の場合はヒープへフォールバックします。したがって

process3
は、
lengthGuess
が 32 バイト以内に収まる場合に ゼロヒープ割り当て を実現できます(推測と実際の要素数が一致すれば)。


append で自動的にスタック割り当て

API に長さ推測を公開したくない場合は、Go 1.26 にアップグレードしてください:

func process(c chan task) {
    var tasks []task
    for t := range c {
        tasks = append(tasks, t)
    }
    processAll(tasks)
}

Go 1.26 ではコンパイラが 仮想的に小さなバックアップストア をスタック上に確保し、

append
の場所で直接使用します。最初の反復でスタックベースのストア(例:長さ 4)が割り当てられ、以降はそれを再利用し続けます。容量が足りなくなるとヒープ割り当てに切り替わります。この手法はサイズ 1・2・4 の初期割り当てとそのガベージを排除します。


スライスが逃げる場合のスタック割り当て

スライスが「逃げる」—例えば関数から返す時 — バックアップストアはスタックに存在できません:

func extract(c chan task) []task {
    var tasks []task
    for t := range c {
        tasks = append(tasks, t)
    }
    return tasks
}

手作業で最適化したバージョンでは、最後にヒープスライスへコピーします。

func extract2(c chan task) []task {
    var tasks []task
    for t := range c {
        tasks = append(tasks, t)
    }
    tasks2 := make([]task, len(tasks))
    copy(tasks2, tasks)
    return tasks2
}

Go 1.26 はこの変換を自動で行います:

func extract3(c chan task) []task {
    var tasks []task
    for t := range c {
        tasks = append(tasks, t)
    }
    tasks = runtime.move2heap(tasks)
    return tasks
}

runtime.move2heap
はコンパイラ-ランタイムの特別関数で、元がスタック割り当てならヒープへコピーし、そうでなければそのまま返します。したがって、要素数が小さくスタックバッファに収まる場合は 正確に必要なサイズだけ の 1 割り当てを行い、オーバーフロー時のみ通常の倍増戦略へ戻ります。


結論

スライスサイズを事前に正確に知っている場合には手作業で最適化する価値がありますが、多くのケースはコンパイラが自動的に処理してくれます。もし最適化が不具合や逆に性能低下を招いたら、

-gcflags=all=-d=variablemakehash=n
でオフにできます。無効化が効果的なら issue を提出してください。

備考:Go スタックは動的サイズのスタックフレーム(alloca 等)を持たず、すべてのスタックフレームは定数サイズです。

同じ日のほかのニュース

一覧に戻る →

2026/02/28 4:08

Googleを辞めたことが、私の生活を実際に良くしてくれました。

## Japanese Translation: 著者は、Google が検索、メール、およびその他のサービスで拡大する支配力がプライバシーとコントロールの問題となり、ユーザーをテック・ジャイアントから離れるよう促していると主張しています。彼らは、2023年5月に追加された「AIオーバービュー」や2026年1月にGmailで導入された生成的 AI など、Google がデータ収集を拡大しつつある証拠として最近の AI 主導機能を指摘しています。筆者は Brave と DuckDuckGo が検索の90%以上を上回っている一方で、Apple は iOS 上で Google をデフォルト検索エンジンに維持するために年間約200億ドルを支払っており、Chrome OS は約70%の使用率で支配していると述べています。これは広告収益が直接支払いを行わないユーザーを製品化する様子を示しています。 著者はプライバシー重視の代替手段を強調しています:メールなら ProtonMail、Fastmail、Tuta(および Mailbox)、動画なら Curiosity Stream、Nebula、Floatplane、Spotify、Dropout ですが、YouTube は Google が所有しているため競合が存在せず例外であると指摘しています。Google を離れた後、著者はデジタル衛生の改善を報告しています:一度きりのサインアップに主要メールアドレスを使用しないことや、より慎重なアカウント作成が増えています。記事は、人々が Google のダークパターンと習慣形成戦術を認識するにつれて、これら代替手段への採用が拡大し、テック業界がより透明でプライバシー尊重型サービスを提供するよう促されるだろうと予測しています。

2026/02/27 23:56

**OpenAI、$730 B のプレマネー評価で 1,10 億ドルを調達**

## Japanese Translation: **要約** OpenAIは、記録的な1,100億ドルのプライベート資金調達ラウンドを閉鎖し、プレマネーバリュエーションを7300億ドルに引き上げました。この取引は、Amazon(500億ドル+AGI実現または年末までにIPOが達成された場合に最大350億ドルのオプション付き)とNvidia(300億ドル)、SoftBank(300億ドル)が主導しています。OpenAIは追加投資家向けにラウンドを開放し続けています。 Amazonの投資には、Bedrock AIサービス上での新しい「ステートフルランタイム環境」、AWSコンピューティング支出の38億ドルから100億ドルへの拡大、少なくとも2GWのTrainium推論ハードウェア使用のコミットメント、およびAmazon消費者製品向けカスタムモデル構築が含まれます。Nvidiaは、Vera Rubinシステムで3GWの専用推論容量と2GWのトレーニングを提供し、正確な資金配分は未公開です。 これは、2025年3月に3000億ドル評価額で400億ドルを調達した以前のラウンド(当時最大のプライベート調達)に続くものです。Amazon CEOのAndy JassyはAIアプリとエージェント開発への協力の影響を強調し、Nvidia CEOのJensen Huangは1月にOpenAIへの大規模サポートを再確認しました。このイベントは2026年6月9日にボストン(MA)でTechCrunchによって報道されました。

2026/02/28 1:33

**NASA、アーテミス計画の全面的な見直しを発表:安全性への懸念と遅延が背景に**

## Japanese Translation: NASAは、アーテミス月面計画を再設計し、統合システムテストのために2027年に専用フライトを追加し、最初の有人着陸を2028年まで延期しました。この改訂により、将来のミッションは単一で低出力の上部段(実質的にExploration Upper Stage (EUS) を廃止)を中心に統合され、Block 1 SLS 構成が継続使用されます。これにより、複数のロケットバリエーションと高い打ち上げガントリーの必要性が排除されました。この改訂は、航空宇宙安全諮問委員会(Aerospace Safety Advisory Panel)の報告書で「過度にリスクがある」とされた元計画を受けており、アーテミス II の水素漏れやヘリウム充圧問題などの技術的障害に対応しています。Apollo 9 の軌道テスト手法を模倣することで、NASA は複雑さを削減しつつ信頼性を確保することを目指しています。 商業パートナーである SpaceX、Blue Origin、Boeing、ULA、および Lockheed Martin は改訂されたスケジュールを受け入れ、SLS ミッションの年次打ち上げペースを支えるようになりました。2027 年にアーテミス III が1つまたは両方のランダーとドッキングして統合テストを行い、その後の 2028 年(アーテミス IV と V)のフライトでは準備が整ったランダーを使用します。NASA は年次ペースを維持するために労働力と技術能力を再構築し、打ち上げリスクとコストを低減する計画です。 この変更は Isaacman の「軌道経済」ビジョンも推進し、空間運用からより多くの価値を引き出して持続可能な月面存在を支援し、永続的な税金負担に依存しない構造を実現します。全体として、新しいアーキテクチャはインフラストラクチャを合理化し、宇宙飛行サービスの新たな商業機会を開きつつ、NASA の長期的探査目標を維持しています。

スタック上で割り当てる(配分する) | そっか~ニュース