プログラムメモリのレビュー
プログラムは 2 つの方法でメモリを割り当てます:
-
スタック: ローカル変数のための連続したメモリ領域。
- 値のサイズは固定で、コンパイル時にわかります。
- 非常に高速: スタックポインタを動かすだけです。
- 管理が容易: 関数呼び出しに従います。
- メモリ局所性が高いです。
-
ヒープ: 関数呼び出しの外にある値を格納する領域。
- 値のサイズは動的で、実行時に決まります。
- スタックよりわずかに低速: 多少の管理処理が必要です。
- メモリ局所性は保証されません。
例
String を作成すると、固定サイズのメタデータはスタックに、動的なサイズの データ、つまり実際の文字列はヒープに配置されます:
// Copyright 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 fn main() { let s1 = String::from("Hello"); }
-
Stringは内部的にVecによって実装されているため、capacity と length を持ち、 可変であれば、ヒープ上での再割り当てによって拡張できることに触れてください。 -
学生からそれについて質問があれば、基盤となるメモリは System Allocator を使用してヒープに 割り当てられており、カスタムアロケータは Allocator API を使って 実装できることを説明できます
さらに詳しく
unsafe Rust を使うとメモリレイアウトを調べられます。ただし、これが当然 unsafe であることは指摘しておくべきです!
// Copyright 2023 Google LLC // SPDX-License-Identifier: Apache-2.0 fn main() { let mut s1 = String::from("Hello"); s1.push(' '); s1.push_str("world"); // 家でこれを試さないでください!教育目的のみです。 // String はそのレイアウトについて何の保証もしないため、これにより // 未定義動作が発生する可能性があります。 unsafe { let (capacity, ptr, len): (usize, usize, usize) = std::mem::transmute(s1); println!("capacity = {capacity}, ptr = {ptr:#x}, len = {len}"); } }