00. Rust 内存管理
通常我们都晓得像 C/Cpp 这类语言, 需要手动管理内存, 但是同样地也很容易出现内存管理不当引发的问题, 譬如空指针, 野指针之类的东西. 然后就发展出了带 Garbage Collection(垃圾回收) 的语言. 但是 GC 这个玩意最明显的地方就是运行时占用内存比较大, 还有就是回收的时候会停顿. 要是应用对性能敏感的话, 还停顿一下, 有点要命. 或者应用是跑在小内存设备上的.
现在我们要是有一门语言, 又不需要 GC, 还能保证内存安全, 那就赞了. 刚好 Rust 符合要求.
常见的内存错误
Segmentation fault
一般的 C/Cpp 程序很容易制造内存错误, 譬如这段代码.
#include <stdio.h> #include <string.h> int main(int argv, char **argc) { char *str = "hello, world"; strcpy(str, "hello, rust"); printf("%s\n", str); return 0; } 复制代码
表面上看不出问题, 直接编译也通过了, 但是一执行就error
了.
如果要揪其原因, 我们先编译之后再通过 objdump 看看.
Section __cstring
在Segment __TEXT
内
这里会出现错误是因为__TEXT
是一个可读可执行区域, 但是这段代码想给这个区域写数据, 等于讲没有这方面的权限, 最明显的反应就是进程非正常退出了.
$ gcc xxx.c -g -Wall $ objdump -s a.out Contents of section __cstring: 100000f90 68656c6c 6f2c2077 6f726c64 0068656chello, world.hel 100000fa0 6c6f2c20 72757374 0025730a 00lo, rust.%s.. $ size -x -l -m a.out Segment __TEXT: 0x1000 (vmaddr 0x100000000 fileoff 0) Section __text: 0x60 (addr 0x100000f00 offset 3840) Section __stubs: 0xc (addr 0x100000f60 offset 3936) Section __stub_helper: 0x24 (addr 0x100000f6c offset 3948) Section __cstring: 0x1d (addr 0x100000f90 offset 3984) Section __unwind_info: 0x48 (addr 0x100000fb0 offset 4016) total 0xf5 复制代码
解引用空指针
当然我们平常开发不会特意这么写. 虽然编译成功了, 但是执行中会发生Segmentation fault
int a = 10; int *p = &a; p = NULL; printf("%d\n", *p); 复制代码
悬空指针
我们这里给 p 申请了一块内存空间, 然后给里面写了些值, 判断 p 不是 NULL, 把 p 指向的区域给 free 了, 但是 p 还是指向那块地址, 这时候 p 就是悬空指针了. 最后打印出了p is not NULL.
假如我们再使用 p 做一些操作, 很可能访问到受保护的内存, 造成Segmentation fault
#include <stdio.h> #include <string.h> int main(int argv, char **argc) { char *p = NULL; p = (char *)malloc(50); strcpy(p, "test"); if (NULL != p) { free(p); } if (NULL != p) { printf("p is not NULL."); } return 0; } 复制代码
......
有些问题很多可以通过规范来避免, 但是没法保证每个人遵守规范. 所以 Rust 设计出来就是为了从语言层面解决内存问题.
又开坑了, 到处挖坑.