0%

堆内存和栈内存

每过一段时间,总是需要一些刺激激励自己前进,不知道自己丢失的是热情还是耐心

今天的问题

局部变量存储在___,全局变量存储在__,动态申请数据存储在__

栈 静态存储区 堆

内存空间

静态存储区(全局变量)

先说最简单的全局变量,包含全局变量和 static 修饰符修饰的静态变量,都是保存在静态存储区当中,并且分为未初始化区域和初始化区域。初始化的全局变量和静态变量保存在一块区域中,未初始化的全局变量和未初始化的静态变量保存在另一块相邻的区域中。

全局变量的生命周期持续到整个程序结束,在程序结束后由系统释放。

对于嵌入式程序来讲,在编译后的 map 文件中就已经确定了全局变量的存储地址位置,通过该 map 文件就可以进行全局变量的调试读取等操作。

栈区(局部变量)

局部变量定义在栈内存中,包括函数的参数值,局部变量定义等。栈区的分配和释放由系统自动进行,分配和释放的速度快,但内存空间也有限,栈区向地址减小的方向增长,分配失败会提示栈溢出错误。栈的内存空间是连续的。

栈也可以手动进行空间分配,使用 alloca 函数进行,但无需程序员进行释放操作。

栈区 windows 下默认在1M左右(VS2010),与编译器有关。

堆区(动态申请数据)

动态申请数据保存在堆内存中,包含 new 和 malloc 分配的空间。由程序员进行手动分配和释放的操作,存储空间大,堆区向地址增大的方向增长,但分配、释放、修改速度慢。

堆区的实现是通过一个链表保存所有空闲的地址空间,在程序进行动态分配内存的时候,根据链表进行检索第一个足够大小的空间分配出去,并从链表中删除此处空间。相对应的在释放的时候同样将释放的空间添加到链表当中去。也因此,堆的内存空间是不连续的,也会因为大量的 new 操作产生内存碎片。

因为堆区的分配和释放完全由程序员手工完成,所以需要特别注意分配的空间必须手动释放掉,防止野指针和无法访问到的内存空间的问题出现。

堆区的大小由程序的32bit或者64bit以及编译器共同决定。32bit程序最大堆大小为2GB,64bit程序在不使用虚拟内存的情况下最大为128GB,开启虚拟内存的情况下理论为16TB。

文字常量区

保存常量字符串的区域。程序结束后由系统释放。

程序代码区

程序代码区,存放二进制代码。

具体问题

1
2
3
4
5
char* p = "Hello World1";
char a[] = "Hello World2";
p[2] = 'A';
a[2] = 'A';
char* p1 = "Hello World1";
  • 行1 中 p 在栈区中,字符串在文字常量区中
  • 行2 中 a 在栈区中,字符串在栈区中
  • 行3 错误,文字常量区中不可修改
  • 行5 中 p1 的值与 p 相等,因为编译器优化将两个相同字符串定义到同一位置

NOTES

  1. 在使用 new 或者 malloc 申请空间后要判断返回值是否为 NULL ,是否正常申请到内存空间。
  2. 为数组和动态申请内存赋初值。
  3. 避免数组下标越界。
  4. 在合适的时间释放 new 或者 malloc 申请的内存空间。
  5. free 或者 delete 空间后,将指向该空间的指针赋值为 NULL ,防止出现野指针。
  6. 避免在栈区(局部变量)定义大数组,使用 malloc 或者全局变量使其定义在堆区或者静态存储区。