面试题答案
一键面试Box
- 内存分配机制:
Box
用于在堆上分配数据,将数据的所有权转移到Box
中。它分配一块连续的内存来存储数据。 - 内存管理机制:当
Box
离开作用域时,它所指向的数据会被自动释放,遵循 Rust 的所有权和生命周期规则。
示例代码:
fn main() {
let b = Box::new(5);
println!("b contains: {}", b);
}
Rc
- 内存分配机制:
Rc
(引用计数)允许在堆上分配的数据被多个所有者共享。它内部除了存储指向数据的指针外,还维护一个引用计数。每次克隆Rc
,引用计数加一。 - 内存管理机制:当
Rc
的引用计数降为 0 时,所指向的数据会被释放。
示例代码:
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = a.clone();
println!("a reference count: {}", Rc::strong_count(&a));
println!("b reference count: {}", Rc::strong_count(&b));
}
Arc
- 内存分配机制:
Arc
(原子引用计数)与Rc
类似,也是通过引用计数来管理内存,允许数据在多个所有者间共享。但Arc
使用原子操作来管理引用计数,这使得它线程安全。 - 内存管理机制:当
Arc
的引用计数降为 0 时,所指向的数据会被释放。
Arc
在多线程环境下相较于 Rc
的优势
Rc
不是线程安全的,因为其引用计数的操作不是原子的,在多线程环境下可能会导致数据竞争。而 Arc
使用原子操作管理引用计数,适合多线程环境。
示例代码:
use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(5);
let handles = (0..10).map(|_| {
let data = data.clone();
thread::spawn(move || {
println!("Thread sees data: {}", data);
})
}).collect::<Vec<_>>();
for handle in handles {
handle.join().unwrap();
}
}
在上述代码中,如果将 Arc
替换为 Rc
,编译时会报错,因为 Rc
不能跨线程传递,而 Arc
由于其原子引用计数机制,可以安全地在多线程环境下共享数据。