static变量初始化时间

  • 在C++中,静态变量分为全局静态变量(属于全局变量)、局部静态变量(函数中的静态变量)和类中静态成员变量。按照初始化的类型分为静态初始化(static initialization)和动态初始化(dynamic initialization)。
  1. 静态初始化
    static initialization:指的是用常量来对静态变量进行初始化,包括zero initialization和const initialization;其中zero initialization的变量会保存在.bss段(未初始化静态变量,以及初始化为0的静态变量);const initialization的变量保存在.data段(已经初始化为非0的静态变量)。对于静态初始化的变量(请注意:包括在函数中采用静态初始化的静态变量),是在程序编译时完成的初始化。

  2. 动态初始化
    dynamic initialization:指的是需要调用函数才能完成的初始化,比如说:int a = foo(),或者是复杂类型(类)的初始化(需要调用构造函数)等,对于这种全局静态变量、类的静态成员变量,是在main()函数执行前,加载时调用相应的代码进行初始化的。而对于局部静态变量,是在函数执行至此初始化语句时才开始执行的初始化(运行时初始化)**。

全局static变量

  1. 如果采用静态初始化,是在编译时完成的初始化,即是在main()函数执行前由运行时调用相应的代码进行初始化的。
  2. 如果采用动态初始化,是由加载时调用的,会在main()函数执行前由运行时调用相应的代码进行初始化的。

局部static变量

  1. 如果采用静态初始化,是在加载时完成的初始化,会在main()函数执行前由运行时调用相应的代码进行初始化的;
  2. 如果采用动态初始化,是在运行时完成的初始化, 是函数执行至此语句完成初始化的

类static成员变量

  1. 如果采用静态初始化,是在加载时完成的初始化,即是在main()函数执行前由运行时调用相应的代码进行初始化的。
  2. 如果采用动态初始化,也是在加载时调用的,会在main()函数执行前由运行时调用相应的代码进行初始化的。

初始化时间

  1. 编译时初始化
  • 在源代码被编译过程中,编译期会加入代码逻辑,以完成确定的内存分配 和 变量的初始化。分配内存,并非实际分配内存,而是写入其内存分配大小信息。
  • 在编译期初始化,那么在实际运行期都是确定的结构和逻辑,将带来更高的性能,因为编译器完成了一定的工作。
  //如:全局变量为内置类型,并且大小确定
  int a=2; 
  static int b=3;  
  static int c=a+b;
  • 是针对于那些简单的、c++内部定义的数据结构(也称 内置结构),如int,double,bool 及 数组结构 的初始化,又可分为两种方式:
    • .bss段 未初始化的变量,也就是我们没指定初值,编译器分配0值给它,编译时编译器将其分配在.bss段,不占用rom空间。
    • .data 段 已初始化的变量,也就是我们指定了初值,编译器将其分配在.data段,占用rom空间。
      注明:bss段不占用rom空间,就是不占用内核镜像的空间,但是在内核加载到内存时,会保留相应的空间。
  1. 加载时初始化
  • 全局类对象在main函数执行前,由加载程序完成其初始化,其无法在编译期初始化,由于那时候还无法调用类的构造函数。同时,在加载期,是线程安全的。例如,饿汉方式的单例类。借助main执行前的加载期完成初始化,由于还在加载,所以确保线程安全。
  1. 运行时初始化
  • 指代实际程序运行期间对象(变量)的创建,包含那些动态创建的对象。由于编译和加载时无法确定大小,因此它们只能延迟到运行期才能完成初始化,将带来程序的性能开销。并且由于运行期间可能是多线程环境,对于共享变量,还可能带来线程安全问题。
  1. 只有采用动态初始化的局部static变量,是在函数执行到此语句时完成初始化的;其余情况的static变量,均会在main()函数执行前执行相应的代码进行初始化,区别仅在于是在编译时执行的相应代码,还是加载时执行的相应代码;
  2. static变量,若类型为复杂类型(类),则采用动态初始化;若为全局的static复杂类型,则在加载时调用,在main()函数之前执行;若为局部的static复杂类型,则在运行时函数执行至此语句完成初始化;
  3. c++规定,const的静态成员可以直接在类内进行初始化,而非const的静态成员需要在类外声明以初始化,对于后一种情况,我们一般选择在类的实现文件中初始化。至此,具体的初始化方式和上面说的是一致的,可在编译期间初始化,也可在运行期间初始化。

初始化顺序

  1. 原则上,定义在任何函数之外的变量(即,全局变量、名字空间变量以及类 static 变量)在main()被调用前初始化。同一个编译单元中的非局部变量按它们的定义顺序进行初始化。
  2. 不同编译单元中全局变量的初始化顺序无法保证一致。因此,在不同编译单元的全局变量初始值顺序间建立依赖关系是不明智的做法。此外,全局变量初始化时抛出的异常也不可能被捕获。一般来说我们最好尽量减少全局变量的使用,特别是限制使用需要复杂初始化的全局变量。
  3. 针对函数内部的局部static变量,其在第一次被调用时初始化,并且只初始化一次。

内存分配时间及释放时间

  • static 成员变量是在初始化时分配内存的,程序结束时释放内存。

C++11 magic static 特性

  • 局部static变量,如果当变量在初始化的时候,并发同时进入声明语句,并发线程将会阻塞等待初始化结束。
  • 这样的话后进入的并发线程一定会阻塞到变量完成初始化后才继续执行,保证了线程安全性。

总结

  • 静态初始化先于动态初始化。因为静态初始化发生在编译时期,直接写进.bss段和.data段,在程序执行时直接加载;而动态初始化则是在运行时期,由运行时库调用相应构造函数进行初始化,同样要写进.bss段或.data段。
  • .data段和.bss段的区别:
    • .data段存放的是已初始化好的全局变量和静态变量;
    • .bss段存放的是未初始化的全局变量和静态变量,给其赋0值【在有些编译器中,初始化为0的静态变量和全局变量也放在.bss段】
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值