Rustには変数の所有権、参照、借用という機能があります。
メモリについてボヤッとでもいいので理解しているほうが、これを理解しやすいと思い、メモリの話を少します。
プログラムを動かすには、4つの領域が必要です。
- プログラム領域: プログラムを置く場所。
- 静的領域: グローバル変数などの静的変数を置く場所。
- スタック領域: 固定長なローカル変数の値を置く場所。
- ヒープ領域: 可変長なローカル変数の値を置く場所。
今回は、このうち変数と関係があるスタック領域とヒープ領域の話をしたいと思います。
メモリ領域は番地管理されている
メモリ領域は、図のように番地で管理されています。
メモリの住所のようなものです。
プログラムは、この番地を使ってメモリ上のデータにアクセスします。
スタック領域
図のように、変数を定義するとスタック領域に変数の情報が格納されます。
- コードと突き合わせたイメージ図 -
しかし、スタック領域にはスカラー型(プリミティブ型)のように、データサイズが固定な型の値しか格納できません。
では、可変長文字列などの変数の値は、どこに格納されるのか?
それは、ヒープ領域に格納されます。
ヒープ領域
可変長文字列などの値はヒープ領域に格納されます。
そして、スタック領域は、データ格納されているヒープ領域のメモリ番地(メモリアドレス)だけが格納されます。
メモリ番地(メモリアドレス)の値は固定長なのでスタック領域に格納できます。
スタック領域、ヒープ領域は有限
大量のデータを処理していて
StackOverflowエラー、OutOfMemoryエラーを発生させてしまったことはないでしょうか。
検証①
StackOverflowエラーはスタック領域がいっぱいになった時に発生するエラーです。
たくさんの変数を宣言した場合や、大きいサイズの固定長の値を格納する変数を定義すると発生させてしまいます。
関数を再帰的に実行して、a2変数を宣言し続けてみた。
fn main() {
let a = 1;
do_something(a);
}
fn do_something(a: i32) {
let a2 = a + 1;
if a2 > 1 {
do_something(a2);
}
}
StackOverFlowのエラーが発生しました。
thread 'main' has overflowed its stack
検証②
OutOfMemoryエラーはヒープ領域がいっぱいになった時に発生するエラーです。
大きいサイズのファイルの一括読み込みや、データベースから一括で大量データを読み込んだ時に発生させてしまいます。
関数を再帰的に実行して、ヒープ領域を消費しみた。
fn main() {
let a = 1;
do_something(a);
}
fn do_something(a: i32) {
let mut vec:Vec<u8> = vec![];
vec.reserve(1024 * 1024 * 1024);
// または
// let mut s = String::with_capacity(1024 * 1024 * 1024);
let a2 = a + 1;
if a2 > 1 {
do_something(a2);
}
}
OutOfMemoryとう表現ではないが、メモリを確保出来なかったエラーが発生しました。
memory allocation of 1073741824 bytes failed