More than 1 year has passed since last update.
Rust 100 Ex 🏃【7/37】 スタック・ヒープと参照のサイズ ~メモリの話~
前の記事
- 【0】 準備 ← 初回
- ...
- 【6】 カプセル化の続きと所有権とセッター ~そして不変参照と可変参照!~ ← 前回
- 【7】 スタック・ヒープと参照のサイズ ~ メモリの話 ~ ← 今回
100 Exercise To Learn Rust 演習第7回になります!
今回の関連ページ
[03_ticket_v1/08_stack] スタック
問題はこちらです。
// TODO: based on what you learned in this section, replace `todo!()` with
// the correct **stack size** for the respective type.
#[cfg(test)]
mod tests {
use std::mem::size_of;
#[test]
fn u16_size() {
assert_eq!(size_of::<u16>(), todo!());
}
#[test]
fn i32_size() {
assert_eq!(size_of::<i32>(), todo!());
}
#[test]
fn bool_size() {
assert_eq!(size_of::<bool>(), todo!());
}
}
今回は各型がメモリ上で専有するサイズ当てゲームですね...!
解説
#[cfg(test)]
mod tests {
use std::mem::size_of;
#[test]
fn u16_size() {
// 16 / 8 = 2
assert_eq!(size_of::<u16>(), 2);
}
#[test]
fn i32_size() {
// 32 / 8 = 4
assert_eq!(size_of::<i32>(), 4);
}
#[test]
fn bool_size() {
// 1バイトあれば足りそう
assert_eq!(size_of::<bool>(), 1);
}
}
16ビットなので2バイト、32ビットなので4バイト、1ビットあれば足りそうだけどマシンの利便性を考慮して1バイト、と回答して実際に当たっています。
スタックの話も是非したいところですが、一般的なコンサイの資料やBookに譲りたいと思います。また第12回で Clone トレイトと Copy トレイトの話をするのですが、 Copy トレイト実装可能要件の一つが「データがスタック上にあること」なので第12回で触れ直す方が実用的な話題だと思うので飛ばします(ん?今全部話してしまったような...?)
[03_ticket_v1/09_heap] ヒープ
問題はこちらです。
pub struct Ticket {
title: String,
description: String,
status: String,
}
// TODO: based on what you learned in this section, replace `todo!()` with
// the correct **stack size** for the respective type.
#[cfg(test)]
mod tests {
use super::Ticket;
use std::mem::size_of;
#[test]
fn string_size() {
assert_eq!(size_of::<String>(), todo!());
}
#[test]
fn ticket_size() {
// This is a tricky question!
// The "intuitive" answer happens to be the correct answer this time,
// but, in general, the memory layout of structs is a more complex topic.
// If you're curious, check out the "Data layout" section of the Rustonomicon
// https://doc.rust-lang.org/nomicon/data.html for more information.
assert_eq!(size_of::<Ticket>(), todo!());
}
}
解説
pub struct Ticket {
title: String,
description: String,
status: String,
}
#[cfg(test)]
mod tests {
use super::Ticket;
use std::mem::size_of;
#[test]
fn string_size() {
// 64bit = 8 byte OS, so usize's size is 8 byte and Strings's one is 8 * 3 = 24
assert_eq!(size_of::<String>(), 24);
}
#[test]
fn ticket_size() {
// intuitive: 24 * 3 = 72
assert_eq!(size_of::<Ticket>(), 72);
}
}
ヒープの話もめっちゃしたいですね...! Box 型とか Vec 型とか String 型とか Rc 型とかはヒープにもメモリがアロケートされます。ヒープに確保されるメモリ量自体は実行時までわからないですが、 ヒープへの参照はスタックに積まれるしサイズがわかる (なので、 Box それ自体は Sized だけど、 Box<T> の T は ?Sized 、つまりサイズ不定でも良い)ということは覚えておくと便利かなって思います。
Vec や String というのはつまり内部にヒープへの参照を持っている型です。
String 型は、以下3つのフィールドを持っています
- ヒープへの参照 ==
usize型の値 -> 64ビットOSなら8バイト - 長さ (length) == 同じく
usize型の値 - 最大長 == 同じく
usize型の値
以上より、String 型は24バイトになります。
そして直感的に、 String 型のフィールドを3つ持つので、 Title 型のスタック上で専有するメモリサイズは72バイトとなります。
直感が当たる場合と当たらない場合があるということですが、これはRustの構造体のメモリ上での確保スペースは最適化されたりされなかったりするという性質のことを指してそうです。
筆者もこの辺の詳細は良くわかっていませんが、とりあえず一つ知っているのはC言語とは異なるということです。FFIのためにC言語の構造体メモリレイアウトに合わせる命令があるので、参考としてリンクを載せておきます。
- 参考: 代替メモリレイアウト
[03_ticket_v1/10_references_in_memory] 参照のメモリサイズ
問題はこちらです。
pub struct Ticket {
title: String,
description: String,
status: String,
}
// TODO: based on what you learned in this section, replace `todo!()` with
// the correct **stack size** for the respective type.
#[cfg(test)]
mod tests {
use super::Ticket;
use std::mem::size_of;
#[test]
fn u16_ref_size() {
assert_eq!(size_of::<&u16>(), todo!());
}
#[test]
fn u64_mut_ref_size() {
assert_eq!(size_of::<&mut u64>(), todo!());
}
#[test]
fn ticket_ref_size() {
assert_eq!(size_of::<&Ticket>(), todo!());
}
}
またまたサイズ当て問題です!
解説
pub struct Ticket {
title: String,
description: String,
status: String,
}
#[cfg(test)]
mod tests {
use super::Ticket;
use std::mem::size_of;
#[test]
fn u16_ref_size() {
assert_eq!(size_of::<&u16>(), size_of::<usize>()); // == 8
}
#[test]
fn u64_mut_ref_size() {
assert_eq!(size_of::<&mut u64>(), size_of::<usize>());
}
#[test]
fn ticket_ref_size() {
assert_eq!(size_of::<&Ticket>(), size_of::<usize>());
}
}
(通常の)参照のメモリサイズは usize と同じなので、 size_of::<usize>() が正解になります。ちなみに 64bit OSはポインタサイズが64ビットなので usize は8バイトを専有します。
では次の問題に行きましょう!
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
