Rustにはガベージコレクターがないことを理解しており、バインディングがスコープ外になったときにメモリがどのように解放されるのか疑問に思っています。
したがって、この例では、Rustがスコープ外になると、「a」に割り当てられたメモリを再利用することを理解しています。
{
let a = 4
}
私がこれに関して抱えている問題は、第一にこれがどのように起こるかであり、第二にこれは一種のガベージコレクションではありませんか?「典型的な」ガベージコレクションとどう違うのですか?
Rustにはガベージコレクターがないことを理解しており、バインディングがスコープ外になったときにメモリがどのように解放されるのか疑問に思っています。
したがって、この例では、Rustがスコープ外になると、「a」に割り当てられたメモリを再利用することを理解しています。
{
let a = 4
}
私がこれに関して抱えている問題は、第一にこれがどのように起こるかであり、第二にこれは一種のガベージコレクションではありませんか?「典型的な」ガベージコレクションとどう違うのですか?
回答:
ガベージコレクションは通常、ヒープがいっぱいに近いか、あるしきい値を超えている場合など、定期的またはオンデマンドで使用されます。次に、アルゴリズムに応じて、未使用の変数を探し、それらのメモリを解放します。
Rustは、変数がスコープから外れるか、コンパイル時にその存続期間が終了するかを認識し、対応するLLVM /アセンブリ命令を挿入してメモリを解放します。
Rustでは、アトミック参照カウントなど、ある種のガベージコレクションも可能です。
new()
Cのような油そそがれた関数はなく、単なる静的関数であり、特にlet x = MyStruct::new()
スタック上にオブジェクトを作成するようなものです。ヒープ割り当ての実際の指標はBox::new()
(またはBoxに依存する構造のいずれか)です。
プログラム内のリソース(メモリを含む)を管理する基本的な考え方は、戦略に関係なく、到達不能な「オブジェクト」に関連付けられているリソースを再利用できるということです。メモリ以外に、これらのリソースには、ミューテックスロック、ファイルハンドル、ソケット、データベース接続などがあります。
ガベージコレクターを備えた言語は、定期的にメモリをスキャンして(何らかの方法で)未使用のオブジェクトを見つけ、それらに関連付けられているリソースを解放し、最後にそれらのオブジェクトによって使用されているメモリを解放します。
RustにはGCがありませんが、どのように管理しますか?
Rustには所有権があります。アフィン型システムを使用して、どの変数がまだオブジェクトを保持しているかを追跡し、そのような変数がスコープ外になると、そのデストラクタを呼び出します。アフィン型システムの効果を簡単に確認できます。
fn main() {
let s: String = "Hello, World!".into();
let t = s;
println!("{}", s);
}
収量:
<anon>:4:24: 4:25 error: use of moved value: `s` [E0382]
<anon>:4 println!("{}", s);
<anon>:3:13: 3:14 note: `s` moved here because it has type `collections::string::String`, which is moved by default
<anon>:3 let t = s;
^
これは、任意の時点で、言語レベルで所有権が追跡されることを完全に示しています。
この所有権は再帰的に機能します。Vec<String>
(つまり、文字列の動的配列)がある場合、それぞれString
がVec
変数または別のオブジェクトなどによって所有されているものによって所有されます。したがって、変数がスコープ外になると、間接的であっても、保持していたすべてのリソースを再帰的に解放します。Vec<String>
これが意味する場合:
String
Vec
自身に関連付けられているメモリバッファを解放するしたがって、所有権の追跡のおかげで、すべてのプログラムオブジェクトの存続期間は、1つ(または複数)の関数変数に厳密に関連付けられ、最終的にはスコープ外になります(それらが属するブロックが終了すると)。
注:これは少し楽観的です。参照カウント(Rc
またはArc
)を使用すると、参照のサイクルを形成してメモリリークを引き起こす可能性があります。その場合、サイクルに関連付けられたリソースが解放されない可能性があります。
手動でメモリを管理する必要がある言語では、スタックとヒープの区別が重要になります。関数を呼び出すたびに、その関数のスコープ内に含まれるすべての変数に対して十分なスペースがスタックに割り当てられます。関数が戻ると、その関数に関連付けられているスタックフレームがスタックから「ポップ」され、メモリは将来の使用のために解放されます。
実用的な観点から、この不注意なメモリクリーニングは、関数のスコープの最後にクリアされる自動メモリストレージの手段として使用されます。
ここで利用可能な詳細情報があります:https: //doc.rust-lang.org/book/the-stack-and-the-heap.html