Rust学习笔记之内存管理

栏目: 编程语言 · Rust · 发布时间: 5年前

内容简介:Rust语言的安全性很大部分来源于其对变量内存的精细化管理,Rust的内存管理技术在GC类语言(eg:Java)和手动释放类语言(eg:C++/C)之间. Rust的所有变量的分布整体上呈现成树状结构,每个变量都有一个唯一的拥有者,这个拥有者的生命周期决定了变量存活的生命周期。这种方式为变量的内存释放和前期安全性检查提供了遍历,但是也同时为编码提出了很多限制。“用户决定每个变量的生命周期,Rust回收变量的内存以及其他相关资源。” – 这是Rust内存管理的最高原则。在Rust中每个value都只有一个单一

Rust语言的安全性很大部分来源于其对变量内存的精细化管理,Rust的内存管理技术在GC类语言(eg:Java)和手动释放类语言(eg:C++/C)之间. Rust的所有变量的分布整体上呈现成树状结构,每个变量都有一个唯一的拥有者,这个拥有者的生命周期决定了变量存活的生命周期。这种方式为变量的内存释放和前期安全性检查提供了遍历,但是也同时为编码提出了很多限制。

1.ownership

变量内存排布及回收原则

“用户决定每个变量的生命周期,Rust回收变量的内存以及其他相关资源。” – 这是Rust内存管理的最高原则。在Rust中每个value都只有一个单一的owner,只有这个owner决定了该值的生命周期。当owner被dropped他的value也会随着被dropped。当变量离开了它的影响返回,它就会被自动回收。下面结合几个常见变量的生命周期进行分析:

  • vector 容器类型的内存分配,
fn print_padovan() {
    let mut padovan = vec![1, 1, 1];// allocated here
    for i in 3 .. 10 {
        let next = padovan[i - 3] + padovan[i - 2]
        padovan.push(next);
    }
    print!("P(1..10)= {:?}", padovan); // dropped here
}

padovan 的内存分配如下, vec类型的变量分配在栈上,其存储的内容分配在堆上,栈上分配内容包括:1. 指正,2. vec的容量大小, 3. vec 当前存储的元素长度

Rust学习笔记之内存管理

  • Box 类型变量的内存分配

普通简单变量直接分配在栈上,通过Box封装的变量存储在堆上,如下例子所示:

{
    let point = Box::new((0.625, 0.5));// point allocated here
    let label = format!(":?", point); // label allocated here
    assert_eq!(label, "(0.625, 0.5)") // both dropped here    
}

Rust学习笔记之内存管理

  • Rust的复杂引用关系会形成一棵ownership树
struct Person {name: String, birth: i32}
    
    let mut composers = Vec::new();

    composers.push(Person{name: "Palestrina".to_string(), birth: 1525});
    composers.push(Person{name: "Downland".to_string(), birth: 1563});
    composers.push(Person{name: "Lully".to_string(), birth: 1632});


    for composer in &composers {
        println!("{}, born {}", composer.name, composer.birth)
    }

在该例子中,变量composers 指向一个vector, vector中的元素是一个结构体,它指向具体结构体的内存结构(参考string类型内存结构和i32类型存储结构)。

Rust学习笔记之内存管理

Rust的ownership 机制总结:

  1. 你可以将一个变量从一个owner转移到另一个owner;
  2. 标准库中提供了 RcArc , 这些允许某些值同时拥有多个owners;
  3. 你可以使用引用( borrow a reference ),但引用是非拥有指针,具有有限的生命周期

move - 变量所属变更机制

在Rust中类似变量赋值、参数传递、或者函数返回值都不会赋值value, 而是采用一种 move 的机制。

move 机制:原owner放弃value的拥有权并转交给destination,并且自身变成未初始化状态;之后destination控制value的生命周期。

ps: 针对 Copy types 都采用复制的方式,默认的 Copy types 有:整型、浮点型、字符型、布尔类型, Copy types 组成的元组以及固定长度的数组也是 Copy tupes

我们来看一个简单的赋值的例子:

let s = vec!["undon".to_string(), "ramen".to_string(), "soba".to_string()]
    let t = s;
    let u = s; // error: use of moved value 's'

t = s 执行之前:

Rust学习笔记之内存管理

t = s 执行之后:

Rust学习笔记之内存管理

ps:

Java 采用可达性分析的方式确定变量的生命周期,复制的直接是引用; Python 中采用引用技术法 复制的也是引用,但是会记录原始变量呗引用的数量; C++ 的赋值操作会直接赋值整个value,会触发相应的复制构造函数,因此开销比较大。相比而言 Rust 采用 move 的机制效率较高,内存管理相对简单,但是统一时间单一变量仅有一个可用引用。

由于使用了 move 的机制,当我们直接使用集合内部元素的时候就会发生控制权的转移,因此为了防止集合内部出现未初始化的变量,rust不允许直接使用集合内部元素进行复制,rust推荐使用引用的方式进行引用相应变量。

还是之前的例子:

let s = vec!["udon".to_string(), "ramen".to_string(), "soba".to_string()];

let t = s[0]; // error[E0507]: cannot move out of borrowed content
    
let m = &[0]; // ok

共享ownership - RcArc

RcArc : 引用技术类型指针,当某些变量需要同时被多个分支使用,且需要在所有使用者使用之后再进行释放的场景。

其中 Arc 是线程安全的,Atomic reference count 而 Rc 则是非线程安全。 Rc 的实现原理是其指向的变量的内容在堆上分配,并且堆上还记录了该变量的引用计数,但是Rc指向的变量必须是不可变。

let s: Rc<String> = Rc::new("shirataki".to_string());

let k: Rc<String> = s.clone();
let u = s.clone();

Rust学习笔记之内存管理

2.引用

引用在Rust中被称为非拥有性(nonowning pointer)指针,这种指针对所指向的对象的生命周期没有影响。

Rust 中创建某个指针也称为borrowing the value: what you have borrowed, you must eventually return to its owner.

引用分两种:

  • 共享引用 : 只能读取被引用的对象,当某个对象有共享引用时,即使是该对象的owner 也不可以修改对象。
let t = &T;
  • 可变引用 : 可以修改被引用的对象内容,可变引用和共享引用是互斥的。
let t = &mut T;

对一个引用的集合的遍历,也会导致循环内部的集合元素的的访问变成相应的引用的方式。

通过引用访问原始值

在Rust中通过引用访问原始值,标准语法需要使用 * 操作符,但是由于引用在Rust中运用广泛, . 操作符也可以做隐式的变量的原始值的获取。

==

引用安全性

Rust中使用引用的时候需要保证引用和其所引用的变量的生命周期是否匹配,需要保证引用的生命周期应该在所引用的变量的生命周期范围内。

可以使用生命周期的限制符限制函数参数或者返回值引用的生命周期范围。 如下所示,<’a> 用来限制所传入函数f的参数p的生命周期应该是局限在函数内部的,也就是说f 中不应该让p赋值给生命周期超过函数的返回的变量。

fn f<'a> (p: &'a i32) {
    // <'a> 表示一个f的生命周期参数
}

如下所示限制了函数的返回值引用的生命周期,表示返回值的生命周期和传入参数的生命周期一致。

fn smallest<'a>(v: &'a [i32]) -> &'a i32 {

}

如下是限制结构体的内变量的生命周期,表示结构体内部r引用的变量的生命周期应该和S保持一致。

struct S<'a> {
    r: &'a i32
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Metasploit渗透测试魔鬼训练营

Metasploit渗透测试魔鬼训练营

诸葛建伟、陈力波、田繁、孙松柏、等 / 机械工业出版社 / 2013-9-1 / 89.00元

首本中文原创Metasploit渗透测试著作,国内信息安全领域布道者和资深Metasploit渗透测试专家领衔撰写,极具权威性。以实践为导向,既详细讲解了Metasploit渗透测试的技术、流程、方法和技巧,又深刻阐释了渗透测试平台背后蕴含的思想。 本书是Metasploit渗透测试领域难得的经典佳作,由国内信息安全领域的资深Metasploit渗透测试专家领衔撰写。内容系统、广泛、有深度,......一起来看看 《Metasploit渗透测试魔鬼训练营》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具