根据Rust 0.5的Tutorial整理,虽然Rust后续还会有变化,但内存模型和三种指针基本固定下来了。
1 Rust的三个目标
Rust的内存模型是为了三个颇具挑战的目标服务的:
内存安全:Rust语言能够操作的内存必须保证有效,正常情况下,Rust不可能触发段错误或者发生内存泄漏。
性能:高性能的低级代码必须能够使用一些不同的内存分配策略。垃圾回收必须是非强制的,而且就算没有使用垃圾回收,也不能违反内存安全。对性能要求不严格的高级代码可以使用单独的、基于GC的、堆内存分配策略。
并发:Rust代码必须免于内存数据竞争。(其他形式的竞争依然可能存在)
2 高效能考量对于内存模型的影响
大部分提供强内存安全的语言都依赖于垃圾回收堆来管理所有对象。这种方法在概念上和实现上都是一种显而易见的思路,但是有很大的代价。基于这种方式的语言大都挣扎于寻求减少内存分配开销的方法(想想Java虚拟机)。Rust通过managed boxes来支持这种方式:在堆上分配的内存整个生命周期都由垃圾回收器管理。
相比之下,类似C++这样的语言对于对象的分配提供了精确的控制。特别是,直接在栈上分配对象,避免了堆上分配的高昂开销。Rust也提供了这样的方式,同时编译器使用clever pointer lifetime analysis来保证当栈对象销毁后,没有变量能够再引用它们。
3 并发考量对于内存模型的影响
并发中的内存安全涉及到两个执行线程对于同一内存的竞争。即使高级语言通常也要求程序员用正确地加锁来避免竞争条件。
Rust则以不同task之间不能共享内存为出发点。其他语言的经验已经证明了:隔离每个task的堆是一个可靠的策略,同时也易于程序员推导程序行为。堆隔离还有一个好处,垃圾回收必须且只能以堆为单位,因此Rust不需要"stop the world"去回收内存。
task的堆之间完全隔离也意味着:task间的任何数据传递必须通过拷贝。尽管拷贝对于task间通讯是一种不错且有效的方式,但是它对于大数据结构来说是很低效的。为了减少数据拷贝,Rust提供了全局交换堆。在交换堆上分配的对象语义上具有所有权,意味着只能有一个单独的变量引用它们。基于这种所有权特性,它们被称为owned boxes。所有的task都可以在交换堆上分配对象,然后将其所有权转交给其他task,避免了拷贝的开销。
1 Rust的三个目标
Rust的内存模型是为了三个颇具挑战的目标服务的:
内存安全:Rust语言能够操作的内存必须保证有效,正常情况下,Rust不可能触发段错误或者发生内存泄漏。
性能:高性能的低级代码必须能够使用一些不同的内存分配策略。垃圾回收必须是非强制的,而且就算没有使用垃圾回收,也不能违反内存安全。对性能要求不严格的高级代码可以使用单独的、基于GC的、堆内存分配策略。
并发:Rust代码必须免于内存数据竞争。(其他形式的竞争依然可能存在)
2 高效能考量对于内存模型的影响
大部分提供强内存安全的语言都依赖于垃圾回收堆来管理所有对象。这种方法在概念上和实现上都是一种显而易见的思路,但是有很大的代价。基于这种方式的语言大都挣扎于寻求减少内存分配开销的方法(想想Java虚拟机)。Rust通过managed boxes来支持这种方式:在堆上分配的内存整个生命周期都由垃圾回收器管理。
相比之下,类似C++这样的语言对于对象的分配提供了精确的控制。特别是,直接在栈上分配对象,避免了堆上分配的高昂开销。Rust也提供了这样的方式,同时编译器使用clever pointer lifetime analysis来保证当栈对象销毁后,没有变量能够再引用它们。
3 并发考量对于内存模型的影响
并发中的内存安全涉及到两个执行线程对于同一内存的竞争。即使高级语言通常也要求程序员用正确地加锁来避免竞争条件。
Rust则以不同task之间不能共享内存为出发点。其他语言的经验已经证明了:隔离每个task的堆是一个可靠的策略,同时也易于程序员推导程序行为。堆隔离还有一个好处,垃圾回收必须且只能以堆为单位,因此Rust不需要"stop the world"去回收内存。
task的堆之间完全隔离也意味着:task间的任何数据传递必须通过拷贝。尽管拷贝对于task间通讯是一种不错且有效的方式,但是它对于大数据结构来说是很低效的。为了减少数据拷贝,Rust提供了全局交换堆。在交换堆上分配的对象语义上具有所有权,意味着只能有一个单独的变量引用它们。基于这种所有权特性,它们被称为owned boxes。所有的task都可以在交换堆上分配对象,然后将其所有权转交给其他task,避免了拷贝的开销。
