2024/01/14

スタックメモリとヒープメモリの使い分けはコンパイラ任せ (1)

golang は chan で時空を超えて(?)値を渡すことができる。

といっても、golang って C言語になかなか近いところがあるので、ポインタで渡すときはヒープにメモリを確保しておかないと危ないよね?
と思って new なり make なり使うべきかと考えていたのだが、ガベッジコレクションもあることを考えるとそう簡単ではない気がした。

 

心配になって検索すると、どうも golang ではスタックメモリやらヒープメモリやらを実装する人が決められないというか、コンパイラが決定するというような記事ばかりが出てくる。

https://duckduckgo.com/?t=ffab&q=golang+stack+heap&ia=web

ただ、そうするとかなりな部分がヒープメモリで管理することになってしまうんじゃなかろうか。いや、関数呼び出しで値がプリミティブだったらスタックにする、みたいなところだけやっておけば十分なのか?

 

よし、忘れよう。

ならば実装する人が気にするのは、値そのものを持つのか、あるいはアドレスで持つのかというところだけになる。
まず、値をリードオンリーで済ませられるかどうか。

  • 値を渡した先でも加工する可能性がある
    • 渡した先でも加工する可能性があるのであれば、それは値そのものを渡す必要がある。
    • 渡した先は参照だけだが、渡された瞬間の値だけがほしいのであれば、それも値そのものを渡した方がよいだろう。アドレスを渡して渡された先がそれを自分でコピーする前に渡した元が加工する可能性があるからだ。
    • 渡した先は参照だけで、渡された元の値の変化も含めて読みたい場合。これならアドレスを渡せばいいと思ったのだけど、そもそも同じメモリ空間をロックせずに読んだり書いたりするというのはダメな行為だ。
  • 値を渡した先は参照のみ
    • 渡した元で値を加工する可能性があるなら、やっぱりアドレスを渡すのは良くないな。

というわけで、プリミティブ型であれば値をそのまま渡してしまえば良いとは思うのだが、CPUのバス幅を超えるようなデータの場合はちょっと考えた方がよいと思う。

 

調べる前に推測してみよう。

chan で渡すデータはアドレスがよいと思う。
なぜなら、値を渡すという行為は何らかのコピーになるのでコストが高いからだ。加工する可能性があるならばchan で渡す前にコピーを作って chan ではコピーしたメモリのアドレスを渡すべきだろう。
コンパイラが賢そうなので、実装する人がそういうのを考慮しなくてもよいのかもしれないが、たぶんそこは実装されたままコンパイルされるんじゃなかろうか。言語仕様としてアドレスにする&があるのだから、そうでなかったらコピーして渡しそうな気はする。ただまあ、それでも実装としてコピーするかコンパイラがコピーするかの違いになるから、あんまり変わらないか、もしかしたら明示的に書いたので最適化できずにコストが高くなってしまう可能性もあるのか...。

さて、推測はした。
答え合わせをしよう。


同じメモリを読み書きするとなると、どうしてもロック・アンロックの機構は必要になる。

どういう単位でアクセスするコンテキストが切り替わるかはわからないが、100バイトあるデータの内50バイト書き換えたタイミングでコンテキストが切り替わる、なんてことも想定しないといかんだろう。
golangではない普通のスレッドモデルで実装していたときだが、32bit の CPU だったのに日付(RTC)を 64bit で持っていて、ごく希に 32bit だけ書き換えたタイミングでコンテキストが切り替わることがあってデータが以上になるということが発生したことがある。あれは痛恨のミスだった。

だから、golang が chan でデータを送りつけるモデルを持つというのはわかりやすかった。
相手が読み取りタイミングで読み取ってほしいけど、こっちはこっちでそのタイミングを気にしたくないということは多いのだ。さっき書いた時刻も getTime() みたいな API を作ってたのでこうなったが、相手が送ってきた最後のデータをこちらが好きなタイミングで読む、だったら問題は少ない。相手が送ってきたデータをこちらが受け取るタイミングと、そのデータをこちらが読み込むタイミングがあるので、そこを共有メモリで実現するなら mutex などでロックする必要がある。が、chan はそういうことがいらないようになっているので現場レベルでは気にしなくてよい。たぶん。

 

そう考えると、chan で渡すデータについては glang でうまいことやってくれるとしても、そこから先は golang がやってくっるとは思えない。
いや、それは私の理解であって golang が実際どうなのかはまだわかっていない。

時間が足りないので次回にしよう。

0 件のコメント:

コメントを投稿

コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。

注: コメントを投稿できるのは、このブログのメンバーだけです。