C语言 内存分配 代码区、常量区、静态区(全局区)、堆区、栈区

1 程序的内存组成

地址区域 作用
代码区 存放程序的代码,即CPU执行的机器指令,并且是只读的。
常量区 存放常量(程序在运行的期间不能够被改变的量,例如: 10,字符串常量”abcde”, 数组的名字等)
静态区(全局区) 静态变量和全局变量的存储区域是一起的,一旦静态区的内存被分配, 静态区的内存直到程序全部结束之后才会被释放
堆区 由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏
栈区 存放函数内的局部变量,形参和函数返回值。栈区之中的数据的作用范围过了之后,系统就会回收自动管理栈区的内存(分配内存 , 回收内存),不需要开发人员来手动管理。栈区就像是一家客栈,里面有很多房间,客人来了之后自动分配房间,房间里的客人可以变动,是一种动态的数据变动。

C语言 内存分配 代码区、常量区、静态区(全局区)、堆区、栈区

2 堆操作与栈操作的比较

堆区:由程序员调用malloc()函数来主动申请的,需使用free()函数来释放内存,若申请了堆区内存,之后忘记释放内存,很容易造成内存泄漏。C语言的灵魂就是指针(灵活!!),而数据结构就决定了malloc()是日常使用的东西,所以堆区是经常会被使用的东西。由程序操作malloc()动态分配的!

C语言 内存分配 代码区、常量区、静态区(全局区)、堆区、栈区

3 堆操作的坏处

堆操作是双刃剑,通过malloc()申请内存去储存我们想要的数据结构,带来了极大的灵活性(可变长度的申请)!但同时,动态分配内存是操作缓慢的、容易造成内存碎片化的。
在早期的微型处理器上,malloc()是不被推荐的(被认为是不可靠的),甚至因为难以管理或者难以实现而不被支持!现如今的微型处理器都很强大,malloc()因为特性也被考虑。

4 从操作系统角度看stack和heap

1 它们在多大程度上受操作系统或语言运行时的控制?
创建线程时,操作系统会为每个系统级线程分配堆栈。通常,语言运行库会调用OS来为应用程序分配堆。

2 他们的范围是什么?
stack连接到线程,因此当线程退出时,stack将被回收。通常,堆是在运行时在应用程序启动时分配的,并在应用程序(技术上已退出)退出时被回收(操作系统有回收内存的专门程序,比如windows)。

3 什么决定了它们的大小?
创建线程时设置堆栈的大小。堆的大小是在应用程序启动时设置的,但是可以随需要的空间而增加(分配器从操作系统请求更多的内存)。

4 是什么使速度更快?
堆栈速度更快,因为访问模式使从中分配内存和取消分配内存变得微不足道(指针/整数只是递增或递减),而堆的分配或释放则涉及到更为复杂的簿记工作。而且,堆栈中的每个字节都倾向于被非常频繁地重用,这意味着它倾向于被映射到处理器的高速缓存中,从而使其非常快。堆的另一个性能损失是,堆(通常是全局资源)通常必须是多线程安全的,即,每个分配和释放都必须(通常)与程序中的“所有”其他堆访问同步。

参考文章:
1、
单片机中,什么是代码区、常量区、静态区(全局区)、堆区、栈区?
2、
堆区和栈区的区别
3、
Stack vs Heap Memory Allocation
4、
What and where are the stack and heap?