essay | tech | year-summary | about

返回上级菜单

Rust Ownership (1)


日期:2021-04-26T00:00:00Z

一直都想写rust的内存管理。恰好要给公司的组内讲解rust,就顺手也摘抄在了这里。

Rust是什么

由火狐浏览器的母公司所创立的新语言,
近年来因为内存安全性和速度受到关注

reverse-complement

source secs mem cpu load
rust 0.45 499,100 23% 24% 64% 61%
c gcc 0.86 698,264 1% 18% 100% 28%

mandelbrot

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倍速度

Rust的速度是如何实现的

(1)基本类型是RAII模式下的unique_pointer和数值复制
(2)heap中的数据类型是RAII模式下的share_pointer
(3)string是存储在string pool中
(4)通过GC来对share_pointer里面计数器为0的变量进行内存释放

Ownership三铁则

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.

宣言heap中的obj会发生什么

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

Move机制

基本类型和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);

Move & Functions

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)
}

Ref

What Is Ownership?