Reference
https://liangyaopei.github.io/2021/01/02/golang-gc-intro/
https://course.rs/basic/ownership/ownership.html
https://www.cnblogs.com/sunsky303/p/16497592.html
https://github.com/0voice/Introduction-to-Golang/blob/main/文章/Go内存分配那些事,就这么简单!.md
回归本源
当我们在写程序的时候,基本上就是向内存写入一些数据,然后利用这些数据来进行操作。那么内存管理就是一个很重要的话题了,操作内存中的对象,其实就是用内存中的一个一个数据来拼积木,一个一个积木被放置在桌上之后,如果没有进行合理的管理,那么桌子很容易就堆积成山了,轻则影响程序的运行效率,重则导致内存占用溢出,导致程序无法运行
堆栈
任何程序最终都是将数据保存在内存的堆或者是栈上的,堆是一种随机存储的内存区域结构,栈是一种顺序存储,先入后出的内存区域结构。光看名字就知道,管理栈始终比管理堆容易得多。而且栈由于数据结构简单有条理,程序可以以很小的开销代替我们管理栈。当一个闭包结束后程序就自动回收这个闭包内部产生的所有栈上的数据
所以一般来说推荐能用栈的时候优先使用栈,由于栈是顺序存储结构,分配一块内存的开销远远比在堆上分配内存来的小
但是栈因为本身能够使用的内存区域是偏小的,限制了递归深度,而且也不适合存储太大的数据。一旦内存占用超过栈的容量,那么就容易发生StackOverFlow()
由于这样或那样的原因,我们不得不使用堆并且手动或者自动管理他
语言原神
提到内存管理,很难不想起来Rust。
在我看来Rust使用了一套全新的机制来“绕过”内存问题。大明鼎鼎的所有权与借用,引用就这样被推至台前
当我们讨论内存安全的时候,常常会提到“悬空指针”这个问题
#include <iostream>
void dangling_pointer_example() {
int* ptr = new int(10); // 动态分配内存
std::cout << *ptr << std::endl; // 输出10
delete ptr; // 手动释放内存
// 此时 `ptr` 已经变成悬空指针,因为内存已被释放
std::cout << *ptr << std::endl; // 未定义行为(可能崩溃或输出垃圾值)
}
int main() {
dangling_pointer_example();
return 0;
}
悬空指针这个问题很大意义上和C++的直接面向底层的设计息息相关,指针只是一个保存内存地址的数据类型,他不关心也无法关心这块数据是在堆上还是在栈上,也不知道这块地址发生了什么变化
可以想象一个拆迁队收到了一个拆迁通知,今天他们要拆除一个危房,但是这危房早就被发生了变化,已经建成了一座新房,但是指针并不知道,拆迁队只是盲目的将新房拆除了,结果明显是灾难性的
在Go语言里面,这个问题被巧妙地解决了:首先,Go语言不允许你像C++一样在堆上开辟内存地址并返回一个底层指针(除非unsafe),其次,当你返回指向栈上创建的数据的内存的指针的时候(而且这个作用域结束了他的生命周期),这个栈上的数据将会逃逸到堆上,指针将指向堆上的内存地址。
而在Rust里面,理念由运行时转向了编译时。需要解决的问题是:如何让编译器知道什么是对的,什么是错的
回到悬空指针问题中,首先Rust就禁止了底层指针的使用,转而使用更加安全的“引用”。在C++的内存逃逸实例中,由于作用域结束导致了栈上的数据被回收,让返回的指针指向了一片未知的领域。而在Rust中,引入了所有权概念,函数作用域中返回的变量的所有权转移到了调用这个函数的那个作用域里面(底层原理是拷贝),原本作用域的变量所有权一旦被转移,那么在个作用域就“查无此人”了,也就是说在Rust里面变量的生命周期是显式的,变量的产生和销毁是可以追溯的
在指针问题上,Rust屏蔽了很多指针的危险功能(指针本质上就是指向一片内存的变量,如果不对其加上一定约束,那么使用指针一定是危险的),并将其成为“引用”(和C++那个不同)。阉割版的指针自然没有那么强大了,很多时候都是为了防止变量的所有权传递得太过复杂
引用也不可能造成悬空指针的问题,编译器利用了生命周期的设计确保了引用不可能指向一个已经失效的变量
GC机制
Rust固然nb,但是现在主流语言使用的几乎都是垃圾回收机制,也就是说程序允许自己运行中不断向堆中存储对象而不当场回收,而是买了个“扫地机器人”来自动化完成这项麻烦事,机器人确实方便,但是代价是太占用资源了。你可以想想,在堆上开辟一块内存本身开销已经很大了,GC完成的事情确实在堆上找到无用的数据然后释放,相当麻烦
关于GC机制,以后再仔细研究一下