RustでOption型を入れる大きな配列を作ったときに、もしかしてメモリ倍つかってるんじゃと気になったので確認してみました。
環境
64bit Windows 10, rustc 1.34。
>rustup show
Default host: x86_64-pc-windows-msvc
installed toolchains
--------------------
stable-x86_64-pc-windows-msvc
nightly-x86_64-pc-windows-msvc (default)
active toolchain
----------------
nightly-x86_64-pc-windows-msvc (default)
rustc 1.34.0-nightly (aadbc459b 2019-02-23)
Option型の大きさ
std::mem::sizeofを使うと型のサイズが求められます。i32、Option, i32×4の配列、Option×4の配列のサイズを調べました。
use std::mem;
type Array4 = [i32; 4];
type OArray4 = [Option<i32>; 4];
fn main() {
println!("size of i32 = {}", mem::size_of::<i32>());
println!("size of Option<i32> = {}", mem::size_of::<Option<i32>>());
println!("size of [i32: 4] = {}", mem::size_of::<Array4>());
println!("size of [Option<i32>: 4] = {}", mem::size_of::<OArray4>());
}
実行結果を確認すると、やっぱり容量倍とってますね。
size of i32 = 4
size of Option<i32> = 8
size of [i32: 4] = 16
size of [Option<i32>: 4] = 32
気になったのでi64でも調査。
size of [i64: 4] = 32
size of [Option<i64>: 4] = 64
Noneかどうかで4バイト取るのでは無く、単純に倍の容量を確保するようです。
バイト列の確認
メモリ上の並びも確認しました。
let arr1 :[i32; 4] = [1, 2, 3, 4];
let arr2 :[Option<i32>; 4] = [Some(1), Some(2), None, Some(3)];
println!("arr1 = {:?}", arr1);
let view = &arr1 as *const _ as *const u8;
for i in 0 .. mem::size_of::<Array4>() as isize {
print!("{:02x} ", unsafe {*view.offset(i)});
}
println!("");
println!("arr2 = {:?}", arr2);
let view = &arr2 as *const _ as *const u8;
for i in 0 .. mem::size_of::<OArray4>() as isize {
print!("{:02x} ", unsafe {*view.offset(i)});
}
println!("");
実行結果です。
arr1 = [1, 2, 3, 4]
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00
arr2 = [Some(1), Some(2), None, Some(3)]
01 00 00 00 01 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 03 00 00 00
配列の容量を倍取ってNoneかどうかで0と1を入れています。
メモリの厳しい環境でOption型を使うときは注意しようと思いました。
いかがでしょうか。