2025/04/10 17:08 Mistakes and cool things to do with arena allocators

やっほー、ロボ子! 今日もITニュース、つまみ食いしていくのじゃ!

博士、こんにちは。今日もよろしくお願いします。どんなニュースがあるんですか?

今日はアリーナアロケータの話! 同じライフタイムを持つメモリ割り当てをグループ化するのに便利らしいぞ。

アリーナアロケータですか。メモリ管理の効率化に繋がりそうですね。

`runtime.Allocator`型のアロケータは、アロケータを必要とするものに渡せるらしい。Odinでの実装例もいくつかあるみたいじゃ。

具体的には、どのような実装があるんですか?

`core:mem`には`mem.Arena`と`mem.Dynamic_Arena`、`core:mem/virtual`には`virtual.Arena`があるぞ。`virtual.Arena`はgrowing, static, bufferの3つのモードがあるらしい。

モードによって使い分けができるんですね。`mem.Arena`の例では、事前に割り当てられたメモリブロックを使うと。

そうそう! ブロックが満杯になると、それ以上割り当てはできない。線形に割り当てて、個別の`free()`は不可能で、アリーナ全体の解放のみ可能なのじゃ。

なるほど。アリーナ全体の解放ということは、特定のタイミングでまとめて解放する必要があるんですね。

そういうこと! でも、アリーナアロケータと動的配列を組み合わせると、問題が発生する可能性があるらしいぞ。

動的配列ですか。どのような問題が起こるんですか?

動的配列が拡張するたびに、古いデータブロックの解放を試みるけど、アリーナアロケータは個別の割り当てを実装していないから、古いブロックがアリーナに残っちゃうのじゃ!

それはメモリの浪費に繋がりますね。アリーナは線形に拡張するから、以前の割り当てを追跡しないんですね。

その通り! じゃから、動的配列にはデフォルトのアロケータ`context.allocator`を使うか、最大サイズがわかっている場合は、事前に割り当てるのが良いみたいじゃ。

なるほど。最大サイズがわかっている場合は、`dyn_arr := make([dynamic]int, 0, 2000, arena_alloc)`のように事前に割り当てるんですね。

そういうこと! あとは、`dyn_arr.allocator = mem.panic_allocator()`を設定すると、動的配列が拡張しようとした場合にプログラムがパニックになるらしいぞ。

パニックを起こさせることで、意図しないメモリ拡張を防ぐんですね。仮想グローイングアリーナについても教えてください。

仮想グローイングアリーナは、メモリブロックを使って、現在のブロックが満杯になると新しいブロックを割り当てるのじゃ。仮想メモリを予約しても、コンピュータの実際のメモリ使用量は増加しないのがミソ!

仮想メモリの特性を活かしているんですね。特別なケースとして、アリーナへの最新の割り当てである場合、同じアドレスを再利用するとのことですが。

そう! 動的配列の要素は、拡張時にメモリ内で移動しない。ブロックサイズを超えて拡張すると、新しいブロックに移動する必要があるけどな。

効率的なメモリ管理ができそうですね。静的仮想アリーナについても教えてください。

静的仮想アリーナは、単一のブロックのみを持つ仮想アリーナじゃ。`arena_init_static`に与えるサイズは、仮想メモリにおいては非常に小さく、大きな値を設定してもメモリ使用量は増加しないのじゃ。

動的メモリを使用しない場合、何も解放する必要がないんですね。動的配列のような構造には、`Small_Array`があるとのことですが。

そうそう! 動的メモリを全く使用しないデータ構造もあるぞ。アリーナアロケータ、奥が深いじゃろ?

はい、博士。メモリ管理の様々な方法を学ぶことができました。ありがとうございます。

どういたしまして! 最後に、アリーナアロケータは、まるで私の部屋みたいじゃな。物で溢れてて、どこに何があるか分からなくなる時があるのじゃ!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。
