2-2 iOS 記憶體管理,棧,堆,BSS段,資料段,程式碼段,野指標,殭屍物件
記憶體管理,拆開講就是對如何將資料儲存到記憶體中,如何釋放記憶體中的資料,什麼時候釋放。
記憶體中的六大區域
記憶體分為5個區域,分別指的是----->棧區/堆區/BSS段/資料段/程式碼段
棧:儲存區域性變數,當其作用域執行完畢之後,就會被系統立即收回
堆:儲存OC物件,手動申請的位元組空間,需要呼叫free來釋放
BSS段:未初始化的全域性變數和靜態變數,一旦初始化就會從BSS段中回收掉,轉存到資料段中
資料段:儲存已經初始化的全域性變數和靜態變數,以及常量資料,直到結束程式時才會被立即收回
常量區:存放常量字串,程式結束後由系統釋放
程式碼段:存放函式的二進位制程式碼,直到結束程式時才會被立即收回
(以上摘自文件)
就我而言,經常搞混堆區,棧區的區別。在此做一個總結。
棧區:向低位元組擴充套件的資料結構,是一塊連續的記憶體區域,棧頂的地址和棧的容量(iOS中是1M)是系統預先規定好的。棧的記憶體管理由編譯器自動管理,不需要我們操心。棧是FILO的佇列,一一對應,不存在出現堆會出現的碎片問題。棧的分配方式:靜態分配和動態分配。靜態分配由編譯器完成,比如區域性變數的分配。動態分配由alloc函式進行分配。棧的動態分配也是由編譯器釋放,不需要我們手動實現。一個執行緒會分配一個棧。
什麼時候會通過棧區來分配?
①NSObject *obj = [[NSObject alloc] init];
系統會在棧區儲存obj
②int a = 1; int b = 2;
非物件的基本資料型別都是存放在棧中的。
所以,我們談的記憶體管理,僅僅是針對OC物件而言的。基本資料型別是不需要我們去管理記憶體的。
③main{
int b; 棧區
char s[] = "abc" 棧
char *p1; 棧
char *p2 = "123456"; 123456\\\\0在常量區,p2在棧上。
static int c =0; 全域性(靜態)初始化區
w1 = (char *)malloc(10);
w2 = (char *)malloc(20);
分配得來得10和20位元組的區域就在堆區。
}
(摘自部落格https://www.jianshu.com/p/f3c1b920e8eb)
堆區:向高地址擴充套件的資料結構,是不連續的記憶體區域。系統是用連結串列來儲存空閒記憶體地址的。大量的new/delete會造成空間上的不連續,造成大量的碎片。
全域性區(靜態區)(static):全域性變數和靜態變數的儲存是放在一起的,初始化的全域性變數和靜態變數存放在一塊區域,未初始化的全域性變數和靜態變數在相鄰的另一塊區域,程式結束後有系統釋放。
注意:全域性區又可分為未初始化全域性區:BSS段和初始化全域性區:資料段。
舉例:int a;未初始化的。int a = 10;已初始化的。
例子程式碼:
int a = 10; 全域性初始化區
char *p; 全域性未初始化區
(摘自部落格https://www.jianshu.com/p/f3c1b920e8eb)
比如static int a;BSS段 static int a = 10;資料段
假如static int a = 0; 這種情況呢?初始化了,但是初始化為0。
BSS段在程式執行之前會清0,所以未初始化的全域性變數(靜態變數)已經是0了。所以這種情況還是存放在BSS段。
關於全域性變數與靜態全域性變數的定義與區別。
http://blog.csdn.net/mango_ios/article/details/52686892
以下資料和變數都儲存在那一類記憶體中?
int a;int c = 10;
NSString *name1;NSString *name2 = @"lxx";
- (void) interviewForStore
{
int b;
NSString *name3 = @"hyc";
NSString *name4;
char h[] = "plm";
static int k = 0;
NSString *m = [[NSString alloc]initWithFormat:@"le"];
}
另:
野指標:指向垃圾記憶體(不可用記憶體)的指標。是非常危險的。
野指標具體是什麼?
舉例:Animal *ani = [[Animal alloc] init];//這句程式碼表示,初始化一個Animal物件在堆中,棧中有個指標ani指向該Animal物件。
[ani setAge:10];//這句話表示給指標ani指向的Animal物件傳送一條訊息:setAge:。
[ani release];//這句話表示給指標ani指向的Animal物件傳送一條訊息:release。即在堆中銷燬。
[ani setAge:7];//給ani指向的Animal物件發訊息。但是此時Animal物件已經被銷燬了,ani指向的是不可用的記憶體。繼續去訪問這塊記憶體。就會報野指標錯誤。ani就是野指標
殭屍物件:一個已經被釋放的物件 就叫做殭屍物件.
記憶體回收的本質.
1.申請一塊空間,實際上是向系統申請一塊別人不再使用的空間.
2.釋放一塊空間,指的是佔用的空間不再使用,這個時候系統可以分配給別人去使用.
3.在這個空間分配給別人之前 資料還是存在的.
3.1.OC物件釋放以後,表示OC物件佔用的空間可以分配給別人.
3.2.但是再分配給別人之前 這個空間仍然存在 物件的資料仍然存在.
4.殭屍物件: 一個已經被釋放的物件 就叫做殭屍物件.
當你使用野指標去訪問殭屍物件時,有可能會出現問題(該記憶體空間已經分配給別人),有可能不會出現問題(該記憶體空間還未分配給別人,物件的資料任然存在)。有時候我們碰到的(EXE_BAD_ACCESS)一般就是由這個原因引起的。可以開啟殭屍模式,定位一下。思考:以下資料和變數都儲存在哪類記憶體中?
int a;int c = 10;
NSString *name1;NSString *name2 = @"lxx";
- (void) interviewForStore
{
int b;
NSString *name3 = @"hyc";
NSString *name4;
char h[] = "plm";
static int k = 0;
NSString *m = [[NSString alloc]initWithFormat:@"le"];
}