将从存储方式、生命周期(时间)、作用域(空间) 三个维度来区分它们。
1 存储方式
- 静态存储方式
静态存储方式是 程序一开始运行时就分配存储空间,从程序开始运行到程序结束,存储空间都保持不变的存储方式。 - 动态存储方式
动态存储是 程序在运行时,需要使用时才分配存储空间,不需要使用时立即释放的存储方式。不像静态存储,还未使用的时候就分配,程序结束才收回。
2 进程的内存分区
代码区
存放代码,只读防止运行时被修改。常量区
-
全局(静态)区
- 数据区
静态存储方式下,变量被分配的空间,放在这里的变量已经初始化。 - BSS
同数据区相同,只不过放在这里的变量还没有初始化。
- 数据区
堆
动态存储方式下,变量被分配的空间,它大小并不固定,可动态扩张或缩减。当进程调用alloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用realse释放内存时,被释放的内存从堆中被剔除(堆被缩减)。放在这里的变量需要程序员手动管理(ARC本质上还是属于手动管理)。栈
动态存储方式下,变量被分配的空间,此时变量由操作系统和编译器管理。并不需要人为管理。
3 全局变量 局部变量
C语言中的定义:全局变量是申明在函数之外的变量,局部变量是申明在函数内部,以及函数的形式参数的变量
-
全局变量
- 存储方式:静态存储,存储在全局(静态)区
- 生命周期:静态存储方式决定了其生命周期为 从程序开始运行到程序结束
- 作用域:该程序的所有文件。
-
局部变量
- 存储方式:动态存储, 存储在堆(对象类型)或栈(数据类型)中
- 生命周期:动态存储方式决定了其生命周期为 变量使用期间
- 作用域:方法和函数内,确切的说从申明到遇到 ‘}‘ 为止。
#import "ViewController.h"
int age = 24;//全局初始化区(数据区)
NSString *name;//全局未初始化区(BSS区)
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
int tmpAge;//栈
NSString *number = @"123456"; //123456\0在常量区,*number在栈上。
NSMutableArray *array = [NSMutableArray arrayWithCapacity:1];//分配而来的8字节的区域就在堆中,*array在栈中,指向堆区的地址
NSInteger total = [self getTotalNumber:1 number2:1];
}
- (NSInteger)getTotalNumber:(NSInteger)number1 number2:(NSInteger)number2{
return number1 + number2;//number1和number2 栈区
}
@end
4 全局变量 静态全局变量
全局变量在第3部分已经说明,静态全局变量就是在全局变量的前面加上 static 关键字。
由 static 修饰的 静态全局变量和全局变量的存储方式、生命周期是相同的。但是它们的作用域是不同的,全局变量在所有文件中都可以访问到,而静态全局变量只能在其申明的文件中才能访问到。也就是说,static改变了全局变量的作用域,从而达到对其他文件隐藏变量的目的,这是static的第一个作用。
- 静态全局变量
- 存储方式:静态存储,存储在全局(静态)区
- 生命周期:静态存储方式决定了其生命周期为 从程序开始运行到程序结束
- 作用域:只有申明该变量的文件才可以访问到。
#import "ViewController.h"
NSSting *name = @"jake" //全局变量,在其他文件中通过 extern 关键字 可以访问到。
static NSSting *nikeNmae = @"jeek" //静态全局变量,只可以在本文件中访问到。
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
@end
5 局部变量 静态局部变量
局部变量在第3部分已经说明,静态局部变量就是在局部变量的前面加上 static 关键字。
由 static 修饰的 静态局部变量和局部变量的作用域是相同的。但是它们的存储方式是不同的,存储方式的不同导致了它们的生命周期也是不同的。 也就是说static改变了局部变量的存储方式,从而达到保存变量的目的,这是static的第二个作用。
- 静态局部变量
- 存储方式:静态存储,存储在全局(静态)区
- 生命周期:静态存储方式决定了其生命周期为 从程序开始运行到程序结束
- 作用域:方法和函数内,确切的说从申明到遇到 ‘}‘ 为止。
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 5; i++) {
[self textC];
}
}
- (void)textC{
NSUInteger localInt = 0; //局部变量
static NSUInteger staticLocalInt = 0; //静态局部变量
NSLog(@"局部变量 = %lu,静态局部变量 = %lu",(unsigned long)localInt,(unsigned long)staticLocalInt);
localInt++;
staticLocalInt++;
}
// 运行结果
2017-06-25 21:31:30.583 ARC-Learn[11825:712288] 局部变量 = 0,静态局部变量 = 0
2017-06-25 21:31:30.584 ARC-Learn[11825:712288] 局部变量 = 0,静态局部变量 = 1
2017-06-25 21:31:30.584 ARC-Learn[11825:712288] 局部变量 = 0,静态局部变量 = 2
2017-06-25 21:31:30.584 ARC-Learn[11825:712288] 局部变量 = 0,静态局部变量 = 3
2017-06-25 21:31:30.584 ARC-Learn[11825:712288] 局部变量 = 0,静态局部变量 = 4
//局部变量是动态存储方式,调用textc()时,localInt分配内存,调用结束时立即收回内存,下次调用在重新分配内存。所以数据是无法保存的。
//静态局部变量是静态存储方式,程序开始运行时,staticLocalInt分配内存,只分配这一次内存,也就是说只初始化一次,textc调用结束时并不收回,而是等到程序结束时才收回。
6 总结
想要比较透彻的理解 全局变量、静态全局变量、局部变量、静态局部变量是什么,以及它们的区别,一定要了解
- 两中存储方式:静态存储、动态存储;
- 存储方式的定义不难看出变量的存储方式决定其生命周期
- 进程中的内存分区:代码区、常量区、全局(静态)区、堆、栈;
- 采用静态存储方式的变量存储在全局(静态)区,采用动态存储方式的变量存储在堆(对象类型)、栈(数据类型、指针)
- 局部变量和全局变量是根据它们申明的位置来区分的
- 静态全局变量和静态局部变量分别是在全局变量和局部变量的基础上加上 static 关键字。
- 全局变量、静态全局变量、静态局部变量采用静态存储方式,局部变量采用动态存储方式。
- 对于全局变量来说,static 改变了其作用域;对于局部变量来说,static改变了其存储方式,从而改变了生命周期。因此 static 这个说明符在不同的地方所起的作用是不同的。应予以注意。
7 参考
本文参考了以下博客,向原作者表示感谢!同时本人水平有限,如有错误还请指出,不甚感激!