/note/tech

Goのポインタ渡しは値渡しよりパフォーマンスが良いという誤解

ポインタが実は高価な理由

  • ポインタが指す値にアクセスする際にnilかどうかのチェックが必ず入る
    • ポインタがnilの場合、Goはpanic()をおこす必要があるため
  • ポインタは動的メモリアロケーションの原因になりがち
    • ポインタが指す値はヒープ領域に置かれがち(絶対ではないけど一般的に多い)
    • ヒープ領域は確保にまとまったメモリの検索、解放にGCが必要になるので負荷が高い
  • ポインタは参照の局所性が低くなりやすいため、CPUキャッシュが効きづらい
  • 多くの場合、値のコピーはポインタを使用するオーバーヘッドよりもはるかに安価
    • GoはDuff’s devicesという手法を用いてメモリコピーなどのよくある処理について非常に効率的なアセンブラコードを生成する
    • x86アーキテクチャだと64バイト以下のオブジェクトであれば値のコピーとポインタのコピーはほぼ同じ

小さいオブジェクトのポインタ渡し

[...]値渡しでもポインタ渡しでもパフォーマンスに大きな違いがないことが確認できました。

関数に副作用がないことを示すためにも、小さな構造体は値渡しで渡すのが無難かと思います。

ポインタを返す関数

関数内部で生成した構造体をポインタ渡しで関数外部に渡してしまうと、コンパイラが変数の寿命を判断できなくなり、動的メモリアロケーションが起きてしまいます。

いろいろ書きましたが、ホットパスな処理以外では値渡しでもポインタ渡しでも処理全体へのパフォーマンスにほぼ変化はありません。時期尚早な最適化は開発スピードを下げてしまいます。ベンチマークを取ってみてボトルネックになっている処理が見つかった場合に、不必要なポインタ渡しがないかを探すことをおすすめします。