Rust มีอะไรแทนคนเก็บขยะ?


95

ฉันเข้าใจว่า Rust ไม่มีตัวเก็บขยะและฉันสงสัยว่าหน่วยความจำจะถูกปลดปล่อยขึ้นมาได้อย่างไรเมื่อการผูกไม่อยู่ในขอบเขต

ดังนั้นในตัวอย่างนี้ฉันเข้าใจว่า Rust เรียกคืนหน่วยความจำที่จัดสรรให้กับ 'a' เมื่อมันอยู่นอกขอบเขต

{
    let a = 4
}

ปัญหาที่ฉันพบคือประการแรกสิ่งนี้เกิดขึ้นได้อย่างไรและประการที่สองนี่ไม่ใช่การเก็บขยะหรือไม่? แตกต่างจากการเก็บขยะ 'โดยทั่วไป' อย่างไร?


12
"อายุของวัตถุที่กำหนด" คล้ายกับ C ++
user2864740

@ user2864740 คู่มือนั้นล้าสมัยไปแล้ว เปลี่ยนที่ทันสมัยอาจจะdoc.rust-lang.org/book/references-and-borrowing.html
Veedrac

คำตอบ:


74

โดยทั่วไปการเก็บขยะจะใช้เป็นระยะ ๆ หรือตามความต้องการเช่นหากฮีปใกล้เต็มหรือสูงกว่าเกณฑ์บางส่วน จากนั้นก็มองหาตัวแปรที่ไม่ได้ใช้และเพิ่มหน่วยความจำของพวกเขาขึ้นอยู่กับขั้นตอนวิธีการ

สนิมจะรู้เมื่อตัวแปรออกนอกขอบเขตหรืออายุการใช้งานสิ้นสุดลงในเวลาคอมไพล์ดังนั้นจึงใส่คำแนะนำ LLVM / แอสเซมบลีที่เกี่ยวข้องเพื่อเพิ่มหน่วยความจำ

สนิมยังช่วยให้ชนิดของการเก็บขยะบางอย่างเช่นการนับอ้างอิงอะตอมแม้ว่า


โดยการจัดสรรหน่วยความจำเมื่อแนะนำตัวแปรและเพิ่มหน่วยความจำเมื่อหน่วยความจำไม่จำเป็นอีกต่อไป? ฉันไม่รู้จริงๆว่าคุณต้องการพูดอะไรกับเรื่องนั้น บางทีเราอาจมีความคิดเห็นที่แตกต่างกันว่า GC คืออะไร
Ayonix

1
คำถามของเขาคือแนวทางของ Rust แตกต่างจาก GC ทั่วไปอย่างไร ดังนั้นฉันจึงอธิบายว่า GC คืออะไรและ Rust ทำอย่างไรหากไม่มี GC
Ayonix

1
doc.rust-lang.org/book/the-stack-and-the-heap.htmlอธิบายได้ดี ใช่มีหลายสิ่งอยู่ในกองซ้อน แต่นับประสาอะไรกับไม่มีตัวบ่งชี้ที่เพียงพอ (ดูกล่อง) ฉันทิ้งมันไว้เพื่อความเรียบง่ายเนื่องจากคำถามมักถาม
Ayonix

1
@Amomum ที่จริง Rust ไม่มีnew()ฟังก์ชันเจิมใด ๆเช่น C เป็นเพียงฟังก์ชันคงที่และโดยเฉพาะอย่างยิ่งบางสิ่งเช่นlet x = MyStruct::new()สร้างวัตถุบนสแต็ก จริงตัวบ่งชี้ของการจัดสรรกองเป็นBox::new()(หรือโครงสร้างที่ขึ้นอยู่กับกล่อง)
Mario Carneiro

1
มีภาษาอื่นใดบ้างที่จัดการการจัดการหน่วยความจำในลักษณะเดียวกับ Rust
still_dreaming_1

43

แนวคิดพื้นฐานในการจัดการทรัพยากร (รวมถึงหน่วยความจำ) ในโปรแกรมไม่ว่าจะเป็นกลยุทธ์ใดก็ตามคือทรัพยากรที่เชื่อมโยงกับ "วัตถุ" ที่ไม่สามารถเข้าถึงได้นั้นสามารถเรียกคืนได้ นอกเหนือจากหน่วยความจำทรัพยากรเหล่านั้นอาจเป็นล็อค mutex ที่จับไฟล์ซ็อกเก็ตการเชื่อมต่อฐานข้อมูล ...

ภาษาที่มีตัวรวบรวมขยะจะสแกนหน่วยความจำเป็นระยะ ๆ (ไม่ทางใดก็ทางหนึ่ง) เพื่อค้นหาวัตถุที่ไม่ได้ใช้ปล่อยทรัพยากรที่เกี่ยวข้องและปล่อยหน่วยความจำที่ใช้โดยวัตถุเหล่านั้นในที่สุด

สนิมไม่มี GC จัดการอย่างไร?

สนิมมีความเป็นเจ้าของ การใช้ระบบประเภท Affineจะติดตามตัวแปรที่ยังคงยึดอยู่กับวัตถุและเมื่อตัวแปรดังกล่าวอยู่นอกขอบเขตจะเรียกตัวทำลายของมัน คุณสามารถดูระบบประเภท affine ได้อย่างง่ายดาย:

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>นี้หมายถึง:

  1. การปล่อยบัฟเฟอร์หน่วยความจำที่เกี่ยวข้องกับแต่ละ String
  2. การปล่อยบัฟเฟอร์หน่วยความจำที่เกี่ยวข้องกับVecตัวมันเอง

ดังนั้นด้วยการติดตามความเป็นเจ้าของอายุการใช้งานของอ็อบเจ็กต์โปรแกรมทั้งหมดจะเชื่อมโยงอย่างเคร่งครัดกับตัวแปรฟังก์ชันหนึ่ง (หรือหลายตัว) ซึ่งท้ายที่สุดจะออกไปนอกขอบเขต (เมื่อบล็อกที่อยู่ในนั้นสิ้นสุดลง)

หมายเหตุ: นี่เป็นแง่ดีเล็กน้อยโดยใช้การนับอ้างอิง ( RcหรือArc) เป็นไปได้ที่จะสร้างวงจรของการอ้างอิงและทำให้เกิดการรั่วไหลของหน่วยความจำซึ่งในกรณีนี้ทรัพยากรที่เชื่อมโยงกับวัฏจักรอาจไม่ถูกปล่อยออกมา


2
"ภาษาที่มีตัวเก็บขยะจะสแกนหน่วยความจำเป็นระยะ ๆ (ไม่ทางใดก็ทางหนึ่ง)" หลายคนทำ แต่นั่นไม่เป็นความจริงโดยทั่วไป เครื่องเก็บขยะแบบเรียลไทม์จะสแกนทีละน้อยแทนที่จะเป็นระยะ อ้างอิงการนับภาษาเช่น Mathematica ไม่สแกนเลย
JD

@JonHarrop: ฉันไม่นับการนับการอ้างอิงเป็นกลไกการเก็บขยะที่สมบูรณ์เนื่องจากต้องเสริมเพื่อหลีกเลี่ยงวงจรการรั่วไหล สำหรับความแตกต่างที่เพิ่มขึ้น / ระยะเวลามันอาจจะใช้ภาษาอังกฤษได้ไม่ดี แต่ฉันไม่เห็นว่าคาบไม่ครอบคลุมกรณีที่เพิ่มขึ้น ... ฉันคิดว่าบิต "(ทางเดียวหรือทางอื่น)" บ่งบอกได้อย่างเพียงพอว่ามีหลายแบบ มีแนวทางอยู่ ไม่ว่าในกรณีใดหากคุณมีวิธีที่ดีกว่าในการอธิบายการเก็บรวบรวมขยะอย่างกระชับโปรดแนะนำให้ไป อย่างไรก็ตามฉันไม่มีความตั้งใจที่จะเปิดตัวด้วยตัวเองในคำอธิบายที่ครบถ้วน: ฉันไม่มีคุณสมบัติสำหรับมัน
Matthieu M.

1
"ฉันไม่นับการนับอ้างอิงเป็นกลไกการเก็บรวบรวมขยะที่สมบูรณ์เนื่องจากต้องเสริมเพื่อหลีกเลี่ยงวงจรการรั่วไหล" RC ถือได้ว่าเป็นรูปแบบของ GC ตามอัตภาพ ตัวอย่างเช่นใน Mathematica และ Erlang ไม่สามารถสร้างวงจรโดยการออกแบบดังนั้น RC จึงไม่รั่วไหล สำหรับมุมมองระดับสูงโปรดดู "ทฤษฎีการรวบรวมขยะแบบรวม" cs.virginia.edu/~cs415/reading/bacon-garbage.pdf
JD

@JonHarrop: จริงถ้าไม่มีรอบเป็นไปได้ RC จะไม่รั่วไหล
Matthieu M.

2
"ฉันไม่เห็นว่าคาบไม่ครอบคลุมกรณีที่เพิ่มขึ้นอย่างไร" อัลกอริทึมการหยุดโลกจะถือเป็นช่วงเวลาในขณะที่การทำเครื่องหมายไตรรงค์ถือได้ว่าเป็นส่วนเพิ่มตัวอย่างเช่น พวกเขาตรงกันข้ามในบริบทนี้
JD

6

ด้วยภาษาที่คุณต้องจัดการหน่วยความจำด้วยตนเองความแตกต่างระหว่างสแต็กและฮีปจึงมีความสำคัญ ทุกครั้งที่คุณเรียกใช้ฟังก์ชันจะมีการจัดสรรพื้นที่เพียงพอบนสแตกสำหรับตัวแปรทั้งหมดที่อยู่ในขอบเขตของฟังก์ชันนั้น เมื่อฟังก์ชันกลับมาสแต็กเฟรมที่เชื่อมโยงกับฟังก์ชันนั้นจะ "โผล่" ออกจากสแต็กและหน่วยความจำจะถูกปล่อยให้ใช้งานในอนาคต

จากมุมมองในทางปฏิบัติการล้างหน่วยความจำโดยไม่ได้ตั้งใจนี้ถูกใช้เป็นวิธีการจัดเก็บหน่วยความจำอัตโนมัติซึ่งจะถูกล้างเมื่อสิ้นสุดขอบเขตของฟังก์ชัน

ดูข้อมูลเพิ่มเติมได้ที่นี่: https://doc.rust-lang.org/book/the-stack-and-the-heap.html


3
แม้ว่าการใช้สแต็กจะมีประโยชน์ แต่อายุการใช้งานของวัตถุที่กำหนดไว้ยังคงสามารถจัดการได้หากค่าทั้งหมดถูก 'สร้างขึ้นบนฮีป' ดังนั้นจึงเป็นรายละเอียดการใช้งาน ไม่จำเป็นต้องเป็นกลยุทธ์ทางภาษา
user2864740

2
คุณใช้คำนั้นไปเรื่อย ๆ ฉันไม่คิดว่ามันหมายความว่าอย่างที่คุณคิด
สวิส

หมายถึงสิ่งที่ฉันต้องการแสดง ; เป็นสิ่งที่ตรงกันข้ามกับช่วงชีวิตที่ไม่ได้กำหนด เสนอข้อเสนอสำหรับวลีที่ดีกว่า
user2864740

ขอบคุณสำหรับคำตอบฉันให้คะแนนคนแรกเพียงเพราะส่งไปก่อน ข้อมูลมีประโยชน์และถูกต้อง
rix

@ user2864740 อายุการใช้งานของวัตถุที่กำหนดหมายถึงความสามารถในการบอกได้อย่างชัดเจนว่าเมื่อใดที่หน่วยความจำของวัตถุจะถูกล้างเมื่อมีการเรียกตัวทำลายล้าง ไม่มีส่วนเกี่ยวข้องกับวิธีการเรียกตัวทำลายนั้นในตอนแรก คุณมักจะพูดคำเดิมซ้ำ ๆ แม้ว่ามันจะไม่มีความสำคัญโดยตรงกับคำถามก็ตาม
สวิส
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.