rust的内存管理

按照内存的管理方式可将编程语言大致分为两类:手动内存管理类和自动内存管理类。
手动管理会有安全问题,比如内存泄漏,内存重复释放,野指针。GC 使用了各种精确的算法来解决内存分配和回收的问题,但并不代表能解决所有的问题。GC 最大的问题是会引起“世界暂停”,GC在工作的时候必须保证程序不会引入新的“垃圾”,所以要使运行中的程序暂停,这就造成了性能问题。
而rust既没有GC高性能,又可以实现安全的内存管理。

先说了一下虚拟内存的概念(每个进程独立的地址空间,以及换入换出扩大内存范围)
然后说了linux内存布局。主要是堆和栈。栈主要保存栈帧,函数调用栈帧的变化过程,局部变量,函数参数都在栈中,栈内存中保存的数据,生命周期都比较短,会随着函数调用的完成而消亡。
但很多情况下会需要能相对长久地保存在内存中的数据,以便跨函数使用,这就是堆内存发挥作用的地方。堆内存是一块巨大的内存空间,占了虚拟内存空间的绝大部分。堆分配的是虚拟内存,真正使用才会分配物理地址。释放也不会立即释放内存。具体分析malloc底层原理。
栈内存肯定比堆内存快,能放在栈上的数据最好不要放到堆上。因此,Rust的类型默认都是放到栈上的。
还介绍了结构体和union内存对齐的规则。

Rust中的资源管理
采用虚拟内存空间在栈和堆上分配内存,这是诸多编程语言通用的内存管理基石,Rust当然也不例外。然而,与C/C++语言不同的是,Rust不需要开发者显式地通过malloc/new或free/delete 之类的函数去分配和回收堆内存。Rust 可以静态地在编译时确定何时需要释放内存,而不需要在运行时去确定。Rust有一套完整的内存管理机制来保证资源的合理利用和良好的性能。

1、对于变量和函数
检测是否声明未初始化变量
对于全局变量,C++会默认初始值,但是对于局部变量,如果没有初始化,就会产生错误的结果。在函Rust编译器可以检查未初始化的变量,以保证内存安全。

2、智能指针和RAII机制
Rust中的指针大致可以分为三种:引用、原生指针(裸指针)和智能指针。
引用就是Rust提供的普通指针,用&和&mut操作符来创建,形如&T和&mut T。原生指针是指形如const T和mut T这样的类型。引用和原生指针类型之间的异同如下。可以通过as操作符随意转换,例如&T asconst T和&mut T asmut T。
智能指针就是基于RAII机制来实现的。使用构造函数来初始化资源,使用析构函数来回收资源。智能指针是对指针的一层封装,提供了一些额外的功能,比如自动释放堆内存。智能指针区别于常规结构体的特性在于,它实现了Deref解引用和Drop 这两个trait

说了半天。内存安全具体是什么?实际上内存泄漏不属于内存安全定义,一次内存泄漏不会有多大影响
使用未定义的内存。因为rust局部变量没初始化编译不通过,所以不会有这个问题。
空指针:空指针不安全,因为虽然空指针可以给程序员判断使用,但是如果没判断直接用就会有问题。Rust中使用Option类型来代替空指针,Option实际是枚举体,包含两个值:Some(T)和None,分别代表两种情况,有和无。这就迫使开发者必须对这两种情况都做处理,以保证内存安全。
垂悬指针:可能造成多次释放内存,Rust的所有权和借用机制解决这个问题
缓冲区溢出:缓冲区可以是栈内存,也可以是堆内存。一般可以使用数组来分配缓冲区。C和C++语言没有数组越界检查机制,当向局部数组缓冲区里写入的数据超过为其分配的大小时,就会发生缓冲区溢出。

但是rust是会有内存泄露存在的:
· 使用引用计数时造成了循环引用(类比于智能指针循环引用问题,用weak_ptr解决)
线程崩溃,析构函数无法调用。这个没办法解决的。
调用forget函数主动泄漏,防止析构出现问题。

总结:rust没有GC,但是利用RAII思想的智能指针来管理自动化管理堆内存。由于RAII机制,使用智能指针在堆上分配内存以后,返回的指针被绑定给栈上的变量,在函数调用完成后,栈帧被销毁,栈上变量被丢弃,之后会自动调用析构函数,回收资源。所以基本不会有内存泄漏。但是不是完全不会。

并且,会有更严格的编译器检查,比如未初始化变量,下标溢出,Option类型来代替空指针,所有权和借用机制解决垂悬指针,来保证内存安全。

你可能感兴趣的:(rust,开发语言,后端)