c++中内存分类

局部变量,存储位置:栈,存储时间:变量所在程序运行时间

全局变量,存储位置:静态存储区,存储时间:程序运行时间

static 静态变量,存储位置:静态数据区,存储时间:第一次初始化到程序运行结束

new 手动分配,存储位置:堆区,存储时间:从new到delete

c++存储空间共分为5个:

静态存储区:程序编译的时候就已经分配好,用于存放全局变量,常量,局部静态变量,全局静态变量

全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。

在 C++ 中 static 的内部实现机制:静态数据成员要在程序一开始运行时就必须存在。因为函数在程序运行中被调用,所以静态数据成员不能在任何函数内分配空间和初始化。只能在main函数之前或者类的定义中进行定义,因为要实际的分配空间,所以不能在类的声明中定义

1、全局静态变量:
定义:.在全局变量之前加上关键字static,全局变量就被定义成为一个全局静态变量。
说明:
1)内存中的位置:静态存储区(静态存储区在整个程序运行期间都存在)
2)初始化:未经初始化的全局静态变量会被程序自动初始化为0(自动对象的值是任意的,除非它被显示初始化)
3)作用域:全局静态变量在声明它的文件之外是不可见的。准确地讲从定义之处开始到文件结尾。
定义全局静态变量的好处:
1)不会被其他文件所访问,修改。
2)其他文件中可以使用相同名字的变量,不会发生冲突。

2、局部静态变量:
定义:在局部变量之前加上关键字static,局部变量就被定义成为一个局部静态变量。
说明:
1)内存中的位置:静态存储区
2)初始化:未经初始化的局部静态变量会被程序自动初始化为0(自动对象的值是任意的,除非他被显示初始化)
3)作用域:作用域仍为局部作用域,当定义它的函数或者语句块结束的时候,作用域随之结束。
注:当static用来修饰局部变量的时候,它就改变了局部变量的存储位置,从原来的栈中存放改为静态存储区。但是局部静态变量在离开作用域之后,并没有被销毁,而是仍然驻留在内存当中,直到程序结束,只不过我们不能再对它进行访问。
当static用来修饰全局变量的时候,它就改变了全局变量的作用域(在声明它的文件之外是不可见的),但是没有改变它的存放位置,还是在静态存储区中。

 

局部静态变量和全局静态变量的作用域为当前文件或当前类变量,不可被其他文件调用,定义范围是函数外,可以在头文件中定义,但是不能在类的声明中定义。

全局变量的作用域为其定义位置开始,至文件结尾,也即只有文件作用域,extern可以扩展全局变量的作用域使其可以被其他的文件调用,定义范围是函数外,可以在头文件中定义

常量是固定值,一经定义无法进行修改,作用域为定义的函数或者文件或者类内,定义范围define为函数外,const为任意位置

test.cpp:

#include<iostream>
#include"test1.hpp"
using namespace std;  
int num5 = 1;//定义全局变量,作用域为当前文件从这一行到下面所有,其他文件可使用extern调用
//static int num4 = 1;//定义全局静态变量,作用域为当前文件,其他文件不可使用extern进行调用
// static int num4;//如果没有初始化,会默认初始化为0
// int Fun(int num1)
// {
//   int num2=0;
//   static int num3=3;//定义局部静态变量,只会初始化一次
//   num2=num2+1;
//   num3=num3+1;
//   return num1+num2+num3+num4;
// }
int main()
{
  int i,num;
  num=2;
  for(i=0;i<3;i++)
  {
    cout<<Fun(num)<<" "<<endl;
  }
  return 0;
}
test.hpp:
#include<iostream>
using namespace std;
extern int num5;
static int num4;//如果没有初始化,会默认初始化为0
#define NUM6 1//定义常量
const int  NUM7 = 1;//定义常量
int Fun(int num1)
{
  int num2=0;
  static int num3=3;//定义局部静态变量,只会初始化一次
  num2=num2+1;
  num3=num3+1;
  return num1+num2+num3+num4+num5+NUM6+NUM7;
}
 
栈区:用于存储局部变量
函数执行结束的时候局部变量自动的释放,栈区效率很高,但是分配的内存容量有限
 
堆区:动态内存分配区
使用new来申请,使用delete来删除,生存期有程序员决定,但是要注意删除,以及删除了之后要将指针指向NULL,防止产生野指针
 
文字常量区:用于存储常量字符串
 
程序代码区:用于存放函数的二进制代码
 

堆与栈的区别:
主要有6点区别:

1、管理方式不同:
对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

2、空间大小不同:
一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改: 打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。 注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。

3、产生碎片不同:
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在它弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。

4、生长方向不同:
对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

5、分配方式不同:
堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,它的动态分配是由编译器进行释放,无需我们手工实现。

6、分配效率不同:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。

从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。 虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。

 

参考(85条消息) C++内存空间:静态存储区、栈、堆、文字常量区、程序代码区_algsup的博客-CSDN博客_c++静态存储区

原文链接: https://www.cnblogs.com/uestc-du/p/17062906.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    c++中内存分类

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/313286

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月16日 下午12:45
下一篇 2023年2月16日 下午12:45

相关推荐