將從存儲方式、生命周期(時間)、作用域(空間) 三個維度來區分它們。
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 參考
本文參考了以下博客,向原作者表示感謝!同時本人水平有限,如有錯誤還請指出,不甚感激!