essay | tech | year-summary | about
日期:2021-04-26T00:00:00Z
一直都想写rust的内存管理。恰好要给公司的组内讲解rust,就顺手也摘抄在了这里。
由火狐浏览器的母公司所创立的新语言,
近年来因为内存安全性和速度受到关注
Linus Torvalds:Linux Kernel 5.14有望整合Rust语言代码 - Linux - cnBeta.COM
一个没有GC的额外消耗的语言
可以媲美c/c++执行效率的语言
| source | secs | mem | cpu load |
|---|---|---|---|
| rust | 0.45 | 499,100 | 23% 24% 64% 61% |
| c gcc | 0.86 | 698,264 | 1% 18% 100% 28% |
| source | secs | mem | cpu load |
|---|---|---|---|
| rust | 0.92 | 32,588 | 99% 100% 100% 100% |
| c clang | 2.09 | 31,812 | 100% 100% 100% 100% |
部分场景甚至要快出2倍速度
(1)基本类型是RAII模式下的unique_pointer和数值复制
(2)heap中的数据类型是RAII模式下的share_pointer
(3)string是存储在string pool中
(4)通过GC来对share_pointer里面计数器为0的变量进行内存释放
Each value in Rust has a variable that’s called its owner.
There can only be one owner at a time.
When the owner goes out of scope, the value will be dropped.
The memory must be requested from the memory allocator at runtime.
We need a way of returning this memory to the allocator when we’re done with our String.
(1)向内存发出请求,请求空间
(2)我们需要得到内存返回的空间,传递给请求空间的变量
(2)中的部分,需要知道何时释放空间的变量。
在c#中是使用GC来对变量进行追踪
在没有GC的语言中,是需要手动释放,如同(1)中一样请求释放
但是问题在于,忘记释放,会造成内存溢出;释放2次,同样是例外。
RUST采用的方式
从内存中返回的内存空间,由变量保持。在变量超出域(scope)时,释放该内存。
该步骤由rust自动完成,rust呼叫drop函数。(类似于c#的dispose)
(和c++中的Resource Acquisition Is Initialization (RAII)原则一样)
{ // s is not valid here, it’s not yet declared
let s = "hello"; // s is valid from this point forward
// do stuff with s
} // this scope is now over, and s is no longer valid
基本类型和obj类型的不同
基本类型是复制,obj类型是move
let x = 5;
let y = x;
let s1 = String::from("hello");
let s2 = s1;
let s1 = String::from("hello");
let s2 = s1;
// error!!!
// error[E0382]: borrow of moved value: `s1`
println!("{}, world!", s1);
如果想复制值,要用clone
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {}, s2 = {}", s1, s2);
如果是基本类型(stack-only-data),直接复制,不采用move
let x = 5;
let y = x;
println!("x = {}, y = {}", x, y);
fn main() {
let s = String::from("hello"); // s comes into scope
takes_ownership(s); // s's value moves into the function...
// ... and so is no longer valid here
let x = 5; // x comes into scope
makes_copy(x); // x would move into the function,
// but i32 is Copy, so it’s okay to still
// use x afterward
} // Here, x goes out of scope, then s. But because s's value was moved, nothing
// special happens.
fn takes_ownership(some_string: String) { // some_string comes into scope
println!("{}", some_string);
} // Here, some_string goes out of scope and `drop` is called. The backing
// memory is freed.
fn makes_copy(some_integer: i32) { // some_integer comes into scope
println!("{}", some_integer);
} // Here, some_integer goes out of scope. Nothing special happens.
fn main() {
let s1 = gives_ownership(); // gives_ownership moves its return
// value into s1
let s2 = String::from("hello"); // s2 comes into scope
let s3 = takes_and_gives_back(s2); // s2 is moved into
// takes_and_gives_back, which also
// moves its return value into s3
} // Here, s3 goes out of scope and is dropped. s2 goes out of scope but was
// moved, so nothing happens. s1 goes out of scope and is dropped.
fn gives_ownership() -> String { // gives_ownership will move its
// return value into the function
// that calls it
let some_string = String::from("hello"); // some_string comes into scope
some_string // some_string is returned and
// moves out to the calling
// function
}
// takes_and_gives_back will take a String and return one
fn takes_and_gives_back(a_string: String) -> String { // a_string comes into
// scope
a_string // a_string is returned and moves out to the calling function
}
fn main() {
let s1 = String::from("hello");
let (s2, len) = calculate_length(s1);
println!("The length of '{}' is {}.", s2, len);
}
fn calculate_length(s: String) -> (String, usize) {
let length = s.len(); // len() returns the length of a String
(s, length)
}