1. 程式人生 > >2-2 iOS 記憶體管理,棧,堆,BSS段,資料段,程式碼段,野指標,殭屍物件

2-2 iOS 記憶體管理,棧,堆,BSS段,資料段,程式碼段,野指標,殭屍物件

記憶體管理,拆開講就是對如何將資料儲存到記憶體中,如何釋放記憶體中的資料,什麼時候釋放。

記憶體中的六大區域

記憶體分為5個區域,分別指的是----->棧區/堆區/BSS/資料段/程式碼段

棧:儲存區域性變數,當其作用域執行完畢之後,就會被系統立即收回

堆:儲存OC物件,手動申請的位元組空間,需要呼叫free來釋放

     BSS段:未初始化的全域性變數和靜態變數,一旦初始化就會從BSS段中回收掉,轉存到資料段中

資料段:儲存已經初始化的全域性變數和靜態變數,以及常量資料,直到結束程式時才會被立即收回

     常量區:存放常量字串,程式結束後由系統釋放

程式碼段:存放函式的二進位制程式碼,直到結束程式時才會被立即收回

(以上摘自文件)

就我而言,經常搞混堆區,棧區的區別。在此做一個總結。

棧區:向低位元組擴充套件的資料結構,是一塊連續的記憶體區域,棧頂的地址和棧的容量(iOS中是1M)是系統預先規定好的。棧的記憶體管理由編譯器自動管理,不需要我們操心。棧是FILO的佇列,一一對應,不存在出現堆會出現的碎片問題。棧的分配方式:靜態分配和動態分配。靜態分配由編譯器完成,比如區域性變數的分配。動態分配由alloc函式進行分配。棧的動態分配也是由編譯器釋放,不需要我們手動實現。一個執行緒會分配一個棧。

什麼時候會通過棧區來分配?

     NSObject *obj = [[NSObject alloc] init];

系統會在棧區儲存obj

物件的指標變數,指向堆區儲存的obj物件。通過alloc函式,在堆區開闢一塊記憶體空間,並生成NSObject記憶體結構的佈局。

     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);

分配得來得1020位元組的區域就在堆區。

     }

     (摘自部落格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"];

}