【wip】プロセスが動作する際のメモリレイアウトを深く理解しよう
プログラマとして押さえておくべき重要なこと。
Log
hr.icon
スタックとヒープとコードの関係
この動画がイメージとしてまずわかりやすいな。
関数が実行される時、スタックフレームが構築され次々コードを読んでいくたびに、スタックメモリにデータを確保していく。
スタックの場合、最初に確定したデータにpushするなんてことはできない。後のデータ配置が崩れてしまうから。
必ず、固定のメモリサイズじゃないとスタックには詰めない。
もしそれを犯してしまうようなコードを書いてると、コンパイルが通らないってことが起きる。
スタックに積まれたデータを後から参照する場合は中身的にはpointerで参照されてる。
相対的なポインタ?が保持されてるか何かで、後で計算に使う時はすぐに取得できるっぽい。
関数の中で別の関数を実行し、戻り値がある場合は、先にreturn_value用のメモリ位置をスタックに確保しておいて、その後に別関数用のスタックフレームを積む。その処理が終わったらスタックフレームを消失させて、結果をreturn_value用のメモリに置いておく。
こんな感じかな?
このスタックの挙動とRustのSizedが何か関係してると思う。
というかそうか、Sizeが不明だとそのデータ用にどれくらいのメモリをスタックに確保すればいいかわからないんだ。
おそらくだが、スタックに積むデータ用のメモリ領域サイズは、実際のデータではなく、型を見て決められてる。
u8なら1バイト分、u16なら2バイト分確保。
中身がどんな値であろうが、型を見てどれくらいの領域を確保するか決めるんだと思う。
だからこそ、Sizeが不明な型は積む際にどれくらいの領域を確保すればいいのか不明で困る。
型で[i32]と指定されても、要素数が指定されてないのでどれくらい確保すればいいのか不明。
Rustではこの状況が許されないってことだろう。
https://scrapbox.io/files/682867e18c77d4a5d625b64a.png
なるほどなonigiri.w2.icon
Rustのリテラル文字列とかは、Initialized Dataに置かれてるんだろうな。
スタックはフラグメンテーションが発生しない
ヒープはフラグメンテーション化が発生する
なんとなく把握した。なるほどな。
まぁいずれにせよ、Stackに詰めるのはサイズが決まったデータ型のみってことだ。
RustでStringとかもSizedって言われるのが少し違和感あると思うが。。。
これはStringの場合、実際には中身はHeapに置かれて、その参照がStackに置かれてるからSizedと言えるってこと。
スタックの動きって何回もやるけど忘れちゃうのよなぁ。
もう一回システムプログラミング周りの理解を深めておいた方がいいかもな。