文章目录
- 一、程序执行内存区域
- 二、堆区详解
- 三、栈内存与堆内存的区别
- 总结
一、程序执行内存区域
**代码区:**当我们的程序被执行时,它会有一个加载准备的过程。其中函数及内部的流程结构代码指令会被放到代码区中,等待着被调用执行。
**常数区:**字符串常量、const 全局变量在程序启动加载时会放置在常数区,被放置在此区域的数据不可被修改,只能读取。
全局区/静态区: 全局变量和代码中的静态变量会在程序启动执行时被加载到此区域。此区域的变量空间只有程序结束关闭后才会被释放。
栈区: 当函数被调用时,其内部的形参、函数内的其它局部变量会被创建在栈区。当函数被调用结束后,配合函数的局部变量就会被操作系统自动释放回收。
堆区: 堆区是由程序员自主管理的内存空间,可以通过 malloc 等函数在堆区内存中申请需要的任意大小的内存空间。但当此内存空间不打算继续使用时,务必使用 free 函数释放掉这些空间,否则在程序关闭以前,这些内存空间是不会被其它程序所使用的,会造成很大的空间浪费甚至宕机。直到程序被关闭后没有手动释放的空间才会被操作系统回收。
二、堆区详解
堆(heap)内存是由程序员根据程序的需要而自行申请的内存空间。堆内存给了程序员极大的自主性使用一片内存空间。但是当程序不需要这个空间时需要及时自行释放申请的堆内存空间。
申请方式(三种):
- malloc 函数用于向堆内存空间申请一片指定字节数量的内存空间,其参数是需要的字节总数量。
free 函数用于释放掉不使用的堆内存空间。 - 还可以用 calloc 函数来实现。其声明语法为:void*calloc(size_t count,size_t,size);
其中第一个参数代表数据成员总数量,第二个参数代表其中一个数据成员所需的空间大小。 - 如果当前的内存空间不够用,想要扩展一下大小。可以使用 realloc 函数。
realloc函数的第一个参数是现有的数据在堆的内存空间地址,第二个参数是扩容后最终空间的总大小。realloc会根据扩容的情况进行空间的处理。如果现有空间的后续空间没有被使用且能够容纳所需的扩容,就在这个基础上扩充。如果不能,就会在堆内存中寻找一段能容纳我们要求大小的新的内存空间,再把现有的内容复制到新的空间,并返回新空间的地址。
malloc 与 calloc 在创建类似数组空间的区别。表面上是参数不同,malloc 需要计算总的空间大小,calloc 则分开设置数量与单个的大小。还有个区别是 calloc 具有空间初始化清零的功能
三、栈内存与堆内存的区别
1、 分配方式与分配效率不同:当函数被调用执行时,其形参与函数体内的局部变量会一起在栈区内全部被创建出来,而堆内存的空间分配是 malloc、calloc 等函数被执行时才会分配空间。从分配效率上讲栈内存高于堆内存。
2、 存储内容不同:堆内存更适用于存储数据量较大的情况,而栈内存更适合存储临时少量的数据。如果函数之间共享一个数据结构(比如链表),那么比较好的处理是把这个数据结构存储在堆内存,栈内存掌握这个堆空间的指针即可,这样就避免了栈空间频繁的创建与回收带来的开销。
3、 管理方式不同:栈内存空间是由操作系统支持管理的,堆内存需要开发者自行维护——创建与回收。如果开发者疏忽了回收就会产生垃圾内存。所以堆内存是容易产生内存碎片的,栈内存由于系统自动维护则不会产生内存碎片。
4、 生长方向与空间大小不同:栈与堆的内存空间都是动态延展的,但它们是相对方向的。栈的内存空间要小于堆的内存空间,所以堆内存空间更适合存储大一些的数据量。
总结
内存管理是一门很重要的学问,感兴趣可以通过侯捷老师的内存管理机制课程深入学习。