在工作的时候,发现有很多细节不注意,会出现各种奇奇怪怪的问题,今天分享全局变量和局部变量的区别,一直觉得自己很清楚两者的不同,不查不知道,一查发现自己还有很多的盲区,知道越多,越觉得自己了解越少,一定要多向前辈们学习才是啊,在此向各位一直在路上的前辈们致敬。
一 全局变量和局部变量的区别
全局变量和局部变量是编程中两种不同作用域的变量,它们的主要区别体现在以下几个方面:
(1)定义位置:
全局变量:在函数外部定义的变量,可以在整个程序中访问。
局部变量:在函数内部定义的变量,只能在该函数内部访问。
(2)生命周期:
全局变量:从定义开始到程序结束,全局变量一直存在。
局部变量:只在函数执行期间存在,函数执行完毕后,局部变量的生命周期结束。
(3)作用域:
全局变量:全局变量具有全局作用域,可以被程序中的任何部分访问(除非被其他同名局部变量遮蔽)。
局部变量:局部变量仅在定义它的函数或代码块内部有效。
(4)内存分配:
全局变量:通常存储在静态存储区,因为它们在整个程序的生命周期中都存在。
局部变量:存储在栈上,当函数被调用时创建,函数返回时销毁。
(5)初始化时机:
全局变量:在程序启动时初始化。
局部变量:在函数调用时初始化。
(6)访问速度:
全局变量:存储在全局命名空间中,通常访问速度较快,因为它们在整个程序的生命周期内存在,不需要重复申请和释放。
局部变量:存储在栈上,它们的访问速度通常也很快,因为它们存储在调用函数的栈帧中,距离CPU较近。但是,每次函数调用时都需要为局部变量分配空间,函数结束后需要释放空间。通常比全局变量访问快,因为它们存储在栈上,距离CPU较近。
(7)内存管理:
全局变量:全局变量在程序的整个生命周期中占用内存,如果全局变量过多,可能会导致内存浪费。需要程序员手动管理内存,不当的使用可能导致内存泄漏。
局部变量:局部变量只在函数调用期间占用内存,函数返回后,局部变量所占用的内存会被释放,这有助于减少内存泄漏的风险。由编译器自动管理,函数结束时自动释放,减少了内存泄漏的风险。
(8)可读性和维护性:
全局变量:由于全局变量可以被程序的任何部分访问和修改,这可能会使得程序的可读性和维护性降低。
局部变量:由于局部变量的作用域限制,它们通常更容易理解和维护。
(9)重用性和冲突:
全局变量:由于全局可见,可能会导致命名冲突。
局部变量:由于作用域限制,减少了命名冲突的可能性。
(10)优化:
全局变量:编译器对全局变量的优化可能不如局部变量,因为全局变量可能被程序的任何部分改变。
局部变量:编译器可以对局部变量进行更多的优化,比如寄存器分配。
二、注意事项
1、 全局变量在不指定初值的情况下自动初始化为0;
2、 在同一源文件中,允许全局变量和局部变量同名,但在局部变量的作用域内,全局变量不起作用。但最好不要重名。
3、 局部变量也称为内部变量;全局变量也称为外部变量,它属于一个源程序文件。
三 、性能对比
在讨论局部变量和全局变量的性能时,我们需要考虑几个因素,包括访问速度、存储位置、以及编译器优化等。以下是一些影响局部变量和全局变量性能的因素:
(1)存储位置:
局部变量:通常存储在栈(Stack)上,栈是高速存储区域,靠近CPU,因此访问速度通常较快。
全局变量:存储在静态存储区(Static Storage Area),对于非静态全局变量,它们可能存储在数据段(Data Segment),这通常比栈慢,因为数据段通常位于RAM中较远的位置。
(2)访问速度:
由于局部变量存储在栈上,它们通常比全局变量访问更快,因为栈的访问速度接近寄存器。
全局变量可能需要更多的内存访问周期来获取,尤其是在多核处理器系统中,全局变量可能不在所有核心的缓存中都有。
(3)编译器优化:
现代编译器可能会对局部变量进行优化,例如将它们存储在寄存器中,这样可以减少访问时间。
对于全局变量,编译器的优化空间较小,因为它们需要在程序的多个部分之间共享。
内存访问模式:
局部变量通常具有更好的局部性(Temporal Locality),因为它们在函数调用期间被频繁访问,这使得它们更有可能被缓存在CPU缓存中。
全局变量可能被程序的不同部分访问,这可能导致缓存行的频繁替换,从而降低性能。
(4)生命周期:
局部变量的生命周期较短,它们在函数调用期间存在,这有助于减少内存泄漏的风险。
全局变量的生命周期与程序相同,不当的管理可能导致内存泄漏。
(5)内存分配和释放:
局部变量在函数调用时分配,在函数返回时释放,这种动态分配和释放可能涉及到一些额外的开销。
全局变量在程序启动时分配,在程序结束时释放,因此没有这种动态分配和释放的开销。
(6)代码结构:
在某些情况下,全局变量可能会被频繁修改,这可能导致编译器难以进行优化。
局部变量通常在函数内部被修改,编译器可以更容易地预测它们的使用模式,并进行优化。
总的来说,局部变量通常比全局变量具有更好的性能,主要是因为它们存储在栈上,访问速度更快,并且更容易被编译器优化。然而,这也取决于具体的使用场景和编译器的优化策略。在性能敏感的应用中,合理地使用局部变量可以提高程序的执行效率。
易混点
1、CPU缓存的影响:
无论是全局变量还是局部变量,现代CPU都会尝试将它们缓存到CPU缓存中,以提高访问速度。这并不是全局变量特有的,局部变量同样受益于CPU缓存。
2、全局变量和局部变量的性能差异主要取决于它们的存储位置和访问模式,而不是是否被CPU缓存。
3、volatile关键字主要用于确保变量的可见性,特别是在多线程环境中,而不是直接禁用CPU缓存。
①volatile关键字的作用:
- volatile关键字在C/C++中用于修饰变量,确保每次访问该变量时都从内存中读取,而不是从CPU缓存中读取。
- volatile关键字的主要目的是确保变量的可见性,特别是在多线程环境中。当一个线程修改了volatile变量时,这个修改对其他线程立即可见。
②volatile与缓存:
- volatile并不直接禁用CPU缓存,而是确保每次访问volatile变量时,都会从内存中读取,而不是从CPU缓存中读取。这可以防止缓存一致性问题,确保变量的修改对所有线程都是可见的。
③volatile与性能:
- 使用volatile关键字可能会降低性能,因为它禁止了编译器和CPU对变量的某些优化,例如缓存和寄存器分配。
- 在单线程程序中,volatile关键字对性能的影响可能不大,但在多线程程序中,它对于确保数据一致性至关重要。
四、补充
经网友提示,在讨论全局变量和局部变量的性能耗时对比的时候,确实需要考虑变量的申请和释放时间,因为这些操作也会影响程序的整体性能。
下面是一些关于全局变量和局部变量性能考虑的因素:
访问速度:
生命周期:
内存管理:
申请和释放时间:
全局变量:全局变量的申请和释放通常在程序启动和结束时进行,因此对性能的影响较小。
局部变量:局部变量的申请和释放在函数调用时进行,如果函数调用频繁,
这些操作可能会对性能产生影响,尤其是在内存紧张的情况下。
作用域和可见性:
优化:
总的来说,局部变量的申请和释放时间确实应该被考虑在内,尤其是在性能敏感的应用中。然而,全局变量和局部变量的选择还应该基于它们的使用场景、生命周期、内存管理需求以及代码的可维护性。在实际编程中,通常会根据具体需求和上下文来选择使用全局变量还是局部变量。
五、关于缓存:
1、CPU缓存的作用和层级
-
减少访问时间:
CPU缓存的主要目的是减少处理器访问内存所需的平均时间。由于CPU的速度远快于内存,缓存作为中间层可以显著提高数据访问速度。 -
金字塔式存储体系:
CPU缓存位于金字塔式存储体系自顶向下的第二层,仅次于CPU寄存器。这种层次结构有助于逐步降低访问延迟和成本。
-
缓存层级:
L1缓存:速度最快,容量最小,通常分为数据缓存和指令缓存。
L2缓存:容量大于L1,速度稍慢,通常包含指令和数据。
L3缓存:容量最大,速度较L2慢,所有CPU核心共享。 -
查找顺序:
CPU在访问数据时,会按照L1、L2、L3的顺序查找,如果都未命中,最后从内存中读取。
2、CPU缓存的问题
-
缓存替换算法:
CPU缓存采用LRU(最近最少使用)和Random等算法来替换缓存行,以优化缓存利用率。 -
缓存命中率:
缓存命中率是指CPU访问缓存时成功找到数据的概率。命中率低意味着更多的数据需要从内存中加载,这会增加延迟。 -
缓存容量限制:
部分CPU只有两级缓存(L1和L2),这意味着可用的缓存空间有限。
3、全局变量与局部变量
- 局部变量的优势:
访问速度:局部变量存储在栈上,通常比存储在全局区域的全局变量访问更快。
缓存利用:局部变量通常具有更好的局部性,因为它们在函数调用期间被频繁访问,更容易被缓存。
- 全局变量的问题:
缓存一致性:全局变量可能被多个线程或函数访问和修改,这可能导致缓存一致性问题。
缓存污染:全局变量的使用可能会占用宝贵的缓存空间,影响其他数据的缓存。
4、结论
由于CPU缓存的这些问题,使用局部变量通常比使用全局变量更有利于提高程序性能。局部变量可以更好地利用缓存,减少缓存替换和提高缓存命中率。因此,建议在可能的情况下优先使用局部变量。
参考文章:
局部变量和全局变量的区别