3.1 OC特性之 記憶體五大區域

来源:http://www.cnblogs.com/ljx-xinge/archive/2017/04/05/31-OC-te-xing-zhi-nei-cun-wu-da-qu-yu.html
-Advertisement-
Play Games

此篇為針對Objective-c語言入門的基礎知識,為了能讓大家更清楚的理解,此整理中編寫了許多的代碼案例和部分截圖,如有錯誤之處,望指正,願與您相互交流學習,共同進步! "會飛的猴子_阿新" (同時還要向刀哥致敬) 本篇目標是: 理解記憶體五大區域及各自的職責 目錄結構 00.簡述 01. 分配和釋 ...


此篇為針對Objective-c語言入門的基礎知識,為了能讓大家更清楚的理解,此整理中編寫了許多的代碼案例和部分截圖,如有錯誤之處,望指正,願與您相互交流學習,共同進步!---"會飛的猴子_阿新" (同時還要向刀哥致敬)

本篇目標是: 理解記憶體五大區域及各自的職責

目錄結構

00.簡述

程式要想執行,第一步就需要 被載入到記憶體中
記憶體五大區域: 棧區,堆區,BSS段(靜態區),常量區(數據段),代碼段.

  1. 棧區: 局部變數和方法實參
  2. 堆區:OC中使用new方法創建的對象,被創建對象的所有成員變數保存在堆區中.
  3. BSS段(也叫靜態區):
    教科書:未被初始化的全局變數和靜態變數.
    Xcode8中: 全局變數和靜態變數,不管有沒有被初始化,都存放在BSS段中.驗證見本篇中的案例.
  4. 常量區(也叫數據段):
    教科書: 存儲已經初始化的全局變數,靜態變數,常量.
    xcode8: 存儲常量
  5. 代碼段: 程式的代碼.
    記憶體五大區域01

01. 分配和釋放(面試常被問到)

  • 棧區 (stack [stæk]): 由編譯器自動分配釋放

    1. 局部變數是保存在棧區的
    2. 方法調用的實參也是保存在棧區的
  • 堆區 (heap [hiːp]): 由程式員分配釋放,若程式員不釋放,會出現記憶體泄漏

    1. 賦值語句右側 使用 new 方法創建的對象
    2. 被創建對象的所有 成員變數
  • BSS 段 : 程式結束後由系統釋放

  • 數據段 : 程式結束後由系統釋放

  • 代碼段:程式結束後由系統釋放

    程式 編譯鏈接 後的二進位可執行代碼

02.棧區和堆區

int main(int argc, const char * argv[]) {

    // 局部變數是保存在棧區的
    // 棧區變數出了作用域之後,就會被銷毀
    NSInteger i = 10;

    NSLog(@"%zd", i);

    // 局部變數是保存在棧區的
    // 賦值語句右側,使用 new 方法創建的對象是保存在堆區的
    // xinge 變數中,記錄的是堆區的地址
    // 在 OC 中,有一個記憶體管理機制,叫做 `ARC`,可以自動管理 OC 代碼創建對象的生命周期
    // 因此,在開發 OC 程式的時候,程式員通常不需要考慮記憶體釋放的工作
    LJXPerson *xinge = [LJXPerson new];
    NSLog(@"%@", xinge);
    return 0;
}

10
<LJXPerson: 0x100404b70>

2.1 棧區

棧區 (stack [stæk]) : 由編譯器自動分配釋放

2.1.1 棧區中的保存(棧區的職責/存儲的內容)

  • 局部變數
  • 方法實參(eg:在main函數中,調用方法,方法中的實參)

2.1.2 棧區的特點

  • 存儲空間有限 . iphone的棧區大小隻有512k(預設) ,非常有限
  • 連續性 . 棧區的地址是連續的
部分代碼:
#import <Foundation/Foundation.h>
#import "LJXPerson.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSInteger i = 10;
        NSLog(@"i 的棧區地址是 %p", &i);
        
        NSInteger j = 10;
        NSLog(@"j 的棧區地址是 %p", &j);
        
        // xiaoming 變數中,存儲的是 LJXPerson 
        對象的記憶體地址(堆區的記憶體地址)
        LJXPerson *xinge = [LJXPerson new];
        NSLog(@"xinge 的棧區地址是 %p", &xinge);
        
        double height = 10;
        NSLog(@"height 的棧區地址是 %p", &height);
        .......

i 的棧區地址是 0x7fff5fbff768
j 的棧區地址是 0x7fff5fbff760
xinge 的棧區地址是 0x7fff5fbff758
height 的棧區地址是 0x7fff5fbff750

  • 地址分配從大到小. 棧區地址按照分配的順序,由大到小順序排列
  • 訪問速度快.
  • 系統管理. (棧區的記憶體由系統管理)

2.1.3 其他

如果在程式中調用方法,會開啟一個  " 棧幀 ".(這個棧幀可以理解為也是一塊連續的區域)

棧幀的地址與之前的局部變數的地址不是連續的棧幀中記錄實參地址,
以及方法內部的局部變數方法執行完畢後,棧幀銷毀(彈棧)   

<<<這樣每次執行完畢後,都彈棧釋放記憶體,這樣就會始終保證棧區占用的記憶體不會特別大>>

so-課外話->我們在開發的時候,如果每個方法都寫的很短,同時每個方法聲明的變數都很少.
這樣做一定會節約記憶體


見圖知意

添加 "在一個函數/方法中"

即在一個函數/方法中最多可定義65536,--->因為"每次"執行完"一個"方法之後就會彈棧釋放記憶體

棧的概念:  後進先出/  先進後出

見圖知意:

NSLog(@"NSInteger 變數占用的位元組數 %tu", sizeof(NSInteger));
        NSLog(@"double 變數占用的位元組數 %tu", sizeof(double));
        NSLog(@"xinge 變數占用的位元組數 %tu", sizeof(xinge));
        
        // 提示:棧區中,只適合存儲非常小的數據
        NSLog(@"在 iPhone 中,最多可以在一個函數/方法中定義 %zd 個局部變數", 512 * 1024 / 8);
        
        // 測試方法調用時,實參在棧區的存儲情況
        [xinge sumWithNum1:i andNum2:j];        

總結:  調用方法時棧區的工作原理
        * 開啟棧幀
        * 保存實參
        * 保存局部變數
        * 方法完成後彈棧,銷毀棧幀,釋放空間

2.2 堆區

堆區 (heap [hiːp]): 由程式員分配釋放,若程式員不釋放,會出現記憶體泄漏

2.2.1 堆區中保存:

  • 使用 new 方法創建的對象保存在堆區
  • 被創建對象的所有成員變數保存在堆區中
堆區的職責是"解決棧區空間有限的問題"

* OC 使用`new`方法創建的對象
--->{由於 **ARC 管理機制**,OC 程式員通常不需要考慮對象的釋放.}
  (在 OC 中,有一個記憶體管理機制,叫做 ARC(自動引用計數)
  可以自動管理 OC 代碼創建對象的生命周期)
* C 語言使用 malloc、calloc、realloc 函數分配的空間,需要使用 free 函數釋放

顧: 在開發 OC 程式的時候,程式員通常不需要考慮記憶體釋放的工作
但是:如果在 OC 的代碼中,如果使用到 C 語言分配空間的函數,則需要考慮釋放記憶體

1. 堆區的大小由系統決定,包括:系統記憶體/磁碟交換空間...
2. 系統使用`鏈表`來管理堆區中的記憶體分配情況
3. {**程式員只需要負責堆區中記憶體的分配和釋放工作**}

2.2.2能夠說出堆區的特點

  1. 所有程式共用
  2. 存儲大數據
  3. 程式員管理: 堆區的記憶體需要程式員管理
  4. 不連續: 堆區的地址是不連續的
  5. 速度沒有棧區快: 堆區的訪問速度沒有棧區快,因為我們要訪問堆區中創建對象的屬性, 必須先需要通過變數找到棧區的地址,再通過地址定位到到堆區中的某一個位置, 只有找個這個位置之後,我們才可以訪問到存儲到這個對象中屬性對應的數值.由於有了 這個地址尋找的過程,所有速度沒有棧區的快.

0.3 全局變數、靜態變數和常量

3.1 全局變數/靜態變數/常量保存的記憶體區域

開發要讓 變化控制在有限的範圍內

3.1.1 教科書中 全局變數 和 靜態變數 的存儲區域

  1. 有初始值的 全局變數 和 靜態變數 保存在 數據段(常量區)
  2. 沒有初始值的 全局變數 和 靜態變數 保存在 BSS 段(靜態區)
    當給 全局變數 或 靜態變數 設置初始值後,會被移動到 數據段(常量區)

3.1.2 Xcode 8 中 全局變數 和 靜態變數 的存儲區域

  1. 無論是否設置初始值全局變數 和 靜態變數 都保存在 BSS 段(靜態區)

  2. 常量 存儲在 數據段(常量區)


註意:(全局/靜態變數,常量)教科書與xcode8驗證有點差別

(1) xcode8 "全局變數"實際存儲區域案例驗證:

案例代碼:

#import <Foundation/Foundation.h>

NSInteger num1 = 10;  //定義第一個全局變數  並且初始化
NSInteger num2;      //定義第二個全局變數   沒有初始化

int main(int argc, const char * argv[]) {
    @autoreleasepool {  
        // 提示:在 Xcode 8 中,全局變數無論是否初始化,地址保持不變
        NSLog(@"第1個全局變數的地址%p", &num1);  //第1個全局變數的地址0x100001188
        NSLog(@"第2個全局變數的地址%p", &num2);  //第2個全局變數的地址0x100001190
        num2=100;
       NSLog(@"第2個全局變數的地址%p(初始化後的)", &num2);
        //第2個全局變數的地址0x100001190(初始化後的)   
    }
    return 0;
}


第1個全局變數的地址0x100001188
第2個全局變數的地址0x100001190
第2個全局變數的地址0x100001190(初始化後的)
Program ended with exit code: 0

可見1:地址從小到大是連續的

可見2:

在 Xcode 8 中,全局變數無論是否初始化,地址保持不變


(2)xcode8 "靜態變數"實際存儲區域案例驗證:

#import <Foundation/Foundation.h>

static NSInteger num1 = 10;  //定義第一個全局變數  並且初始化
static NSInteger num2;      //定義第二個全局變數   沒有初始化

static NSInteger sNum1 = 10;  //定義第一個靜態的全局變數  並且初始化
static NSInteger sNum2;      //定義第二個靜態的全局變數   沒有初始化

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        // 提示:在 Xcode 8 中,全局變數無論是否初始化,地址保持不變
        NSLog(@"第1個全局變數的地址%p", &num1);  //第1個全局變數的地址0x1000011f8
        NSLog(@"第2個全局變數的地址%p", &num2);  //第2個全局變數的地址0x100001208
        num2=100;
        NSLog(@"第2個全局變數的地址%p(初始化後的)", &num2);//第2個全局變數的地址0x100001208(初始化後的)
        NSLog(@"##############################################");
        NSLog(@"第1個靜態的全局變數的地址%p", &sNum1);  //第1個靜態的全局變數的地址0x100001200
        NSLog(@"第2個靜態的全局變數的地址%p", &sNum2);  //第2個靜態的全局變數的地址0x100001210
        sNum2=100;
        NSLog(@"第2個靜態的全局變數的地址%p(初始化後的)", &sNum2);//第2個靜態的全局變數的地址0x100001210(初始化後的)
    }
    return 0;
    }    

第1個全局變數的地址0x1000011f8
第2個全局變數的地址0x100001208
第2個全局變數的地址0x100001208(初始化後的)
################################
第1個靜態的全局變數的地址0x100001200
第2個靜態的全局變數的地址0x100001210
第2個靜態的全局變數的地址0x100001210(初始化後的)
Program ended with exit code: 0

可見1. 靜態變數的初始化前後地址也是不變的

可見2. 靜態變數和全局變數是交叉保存的

so-->面試註意:
   ---->在xcode 8中, 靜態變數和全局變數保存在同一個區域
   ---->在xcode 8中, 靜態變數和全局變數都保存在BSS段中.
   跟我們教課書上是有區別的,
   so-->當面試中遇到這個問題時,我們可以這樣回答:
        在教課書中:BSS段存放的是未被初始化的全局變數和靜態變數,
        但是我們通過xcode8 驗證後,他們不管是全局變數
        還是靜態變數都存儲在BSS段中.
        

(3)xcode8 "常量"實際存儲區域案例驗證:

#import <Foundation/Foundation.h>

       NSInteger num1 = 10;
       NSInteger num2;

static NSInteger sNum1 = 10;
static NSInteger sNum2;
const NSInteger cNum = 10000;//定義一個常量

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"第1個全局變數的地址%p", &num1);
        NSLog(@"第2個全局變數的地址%p", &num2);
        num2=100;
        NSLog(@"第2個全局變數的地址%p(初始化後的)", &num2);
        NSLog(@"##############################################");
        NSLog(@"第1個靜態的全局變數的地址%p", &sNum1);
        NSLog(@"第2個靜態的全局變數的地址%p", &sNum2);
        sNum2=100;
        NSLog(@"第2個靜態的全局變數的地址%p(初始化後的)", &sNum2);
        //第2個靜態的全局變數的地址0x100001230(初始化後的)
        NSLog(@"##############################################");
        NSLog(@"第1個常量的地址%p", &cNum); 
        //第1個常量的地址0x100000e88
    }
    return 0;
}

第1個全局變數的地址0x100001218
第2個全局變數的地址0x100001228
第2個全局變數的地址0x100001228(初始化後的)
#################
第1個靜態的全局變數的地址0x100001220
第2個靜態的全局變數的地址0x100001230
第2個靜態的全局變數的地址0x100001230(初始化後的)
##################
第1個常量的地址0x100000e88
Program ended with exit code: 0

常量存儲演示:面試萬一遇到,可演示一下,解釋與科普書上的不同

可見: 全局變數和靜態變數  跟常量放在不同的區域中,常量存放在常量區(或叫數據段).
*     教科書:數據段(常量區)用來存儲已經初始化的全局變數,靜態變數,常量.
*     xcode8:中數據段(常量區)存放的是常量.

3.2 BSS段(靜態區)

存儲的內容: (前面已經案例驗證過了):
1. 教科書: 存儲未初始化的 全局變數 和 靜態變數
2. Xcode 8驗證: 不管有沒有初始化均存儲 全局變數 和 靜態變數.

3.3 數據段(常量區)

存儲的內容: (前面已經案例驗證過了):

  1. 教科書 :存儲已經初始化的 全局變數、靜態變數、常量

  2. Xcode 8驗證 :不管有沒有初始化均存儲 常量.

3.4 全局變數與全局靜態變數的區別

  1. 若程式只有一個文件全局變數全局靜態變數沒有區別 (程式中只有一個文件,幾乎是不存在的,因為通常一個類就對應2個文件.)
  2. 若程式由多個文件構成時,全局變數全局靜態變數 不同:

  • 全局靜態變數 通常在定義該變數的文件內部使用 註意:

註意:

1.為什麼OC中幾乎不使用 全局變數?
1. 因為程式的任何一個位置都可以對 全局變數 進行修改
2. 一旦程式出現由全局變數產生的錯誤,不好排查錯誤
3. 使用全局變數不是一個好習慣
[我的理解:因為當我們開發時文件有很多,但是又不能把全局變數定義到頭文件中
(如果定義在頭文件中,當別的類引入該頭文件後,相當於在兩個類中都低定義了該全局變數,
會出現重覆定義),所有幾乎不使用.]
2.不能把 全局變數 定義在頭文件中

(我的理解:如果定義在頭文件中,當別的類引入該頭文件後,相當於在兩個類中都定義了該全局變數,會出現重覆定義)

3.在程式開發時,全局變數 和 靜態變數 都不能重名

(我的理解:當跟別的變數重名時,會被重名的變數修改.)

4.靜態變數 的修改通常只是在 定義當前靜態變數的文件 內部進行

外部即使修改,但是由於地址不同,也不會影響到 定義靜態變數文件 內部的數值變化
一旦程式因為 靜態變數 產生錯誤,只需要在當前文件中,檢查一下修改 靜態變數 的代碼即可,排查錯誤難度相對降低

提示:在程式開發時,如果要使用全局的變數,應該在 .m 中定義一個全局的靜態變數,而不要把該變數暴露在頭文件中-->因為變數範圍越小越可控.

------------------LJXPerson.h---------------------
#import <Foundation/Foundation.h>
//
static NSInteger num1 = 99; //定義一個全局靜態變數

@interface LJXPerson : NSObject

/**
 測試方法
 */
- (void)test;
@end

------------------LJXPerson.m---------------------
**LJXPerson.m**
#import "LJXPerson.h"
@implementation LJXPerson

- (void)test{
    num1--;
    NSLog(@"%p   %zd",&num1,num1);
}
@end

------------------main.m-------------------------

 #import <Foundation/Foundation.h>
 #import "LJXPerson.h"
int main(int argc, const char * argv[]) {
    
     //測試全局的靜態變數
    NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
    num1=777777;
    NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
   
    LJXPerson *xinge=[LJXPerson new];
    [xinge test];
    
    LJXPerson *xiaoming=[LJXPerson new];
    [xiaoming test];
    
    NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
    return 0;
}

在LJXPerson中定義的全局靜態變數的地址0x100001190,99
在LJXPerson中定義的全局靜態變數的地址0x100001190,777777
0x100001198 98
0x100001198 97
在LJXPerson中定義的全局靜態變數的地址0x100001190,777777

通過:上面的輸出結果截圖也對剛纔上面的闡述得到了驗證,以下代碼第6,7,8,13,14行是調用的外部的,即修改的是地址0x100001190對應的變數的值,只有在對象調用方法時是調用的內部的靜態變數.

    //測試全局的靜態變數
6.   NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
7.   num1=777777;
8.   NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
   
9.    LJXPerson *xinge=[LJXPerson new];
10.   [xinge test];
    
11.   LJXPerson *xiaoming=[LJXPerson new];
12.   [xiaoming test];

13.   NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
14.   return 0;
}

main函數中:註釋掉下麵的代碼

//    NSLog(@"在LJXPerson中定義的全局靜態變數的地址%p,%zd", &num1,num1);
//    num1=777777;


在LJXPerson中定義的全局靜態變數的地址0x100001190,99
0x100001198 98
0x100001198 97
在LJXPerson中定義的全局靜態變數的地址0x100001190,99

3.5 靜態變數的正確用法

  1. 先定義局部靜態變數
  2. static 關鍵字定義的變數在程式執行中 只會被執行一次
    • 在 BSS 段為變數分配空間
    • 並且設置初始值,如果沒有指定初始值,會使用 0 作為初始值

即: static 關鍵字的作用

  1. 在 BSS 段為 靜態變數 分配空間
  2. 為 靜態變數 設置初始值,如果沒有指定初始值,會使用 0 來作為初始值
  3. static 關鍵字定義靜態變數的代碼,只會被執行一次

------------------聲明---------------------
#import <Foundation/Foundation.h>
@interface LJXPerson : NSObject
/**
 測試方法
 */
- (void)test;
@end
-------------------實現--------------------
#import "LJXPerson.h"
@implementation LJXPerson
- (void)test{
    static NSInteger num1 = 99;  //定義局部靜態變數
    num1--;
    NSLog(@"%p   %zd",&num1,num1);
}
@end
-------------------主程式--------------------
#import <Foundation/Foundation.h>
#import "LJXPerson.h"
int main(int argc, const char * argv[]) {
    
    LJXPerson *xinge=[LJXPerson new];
    [xinge test];
    
    LJXPerson *xiaoming=[LJXPerson new];
    [xiaoming test];

    return 0;
}

2030-03-31 15:12:48.504 demo[5399:535229] 0x100001170 98
2030-03-31 15:12:48.505 demo[5399:535229] 0x100001170 97
Program ended with exit code: 0

3. 如果當前類文件中,有 多個方法 使用到該靜態變數,再將該靜態變數修改成全局的

------------------聲明---------------------
#import <Foundation/Foundation.h>
@interface LJXPerson : NSObject
/**
 測試方法
 */
- (void)test;
- (void)demo;
@end
-------------------實現--------------------
#import "LJXPerson.h"
//當前類文件中,有 `多個方法` 使用到該靜態變數,放到全局中
static NSInteger num1 = 99;

@implementation LJXPerson
- (void)test{
    num1--;
    NSLog(@"%p   %zd",&num1,num1);
}
- (void)demo{
    num1++;
    NSLog(@"%p   %zd",&num1,num1);
}
@end
-------------------主程式--------------------
#import <Foundation/Foundation.h>
#import "LJXPerson.h"
int main(int argc, const char * argv[]) {
    
    LJXPerson *xinge=[LJXPerson new];
    [xinge test];
    [xinge demo];
   
    LJXPerson *xiaoming=[LJXPerson new];
    [xiaoming test];
    [xiaoming demo];
    return 0;
}

0x1000011b0 98
0x1000011b0 99
0x1000011b0 98
0x1000011b0 99

3.6 常量

作用:定義一個固定不變的值,全局統一使用,eg:公司網址,電話等

  1. const 關鍵字保證其後修飾的常量的值不允許被修改
    常量的工作原理:
    在 程式被載入到記憶體時,就會為常量分配空間並且設置初始值
    在 數據段 為常量分配空間
    如果沒有指定初始值,會使用 0 作為初始值

  2. 不能把 常量 定義在頭文件中
    (跟全局變數不能定義在頭文件中一樣,會導致重覆定義)

  3. 應該在 .m 中定義常量
    比如我們在LJXPerson.m中定義了一個常量,const NSInteger cNumber =100;這時,這個常量只能在LJXPerson.m中使用,怎麼才能也能在main.m中使用呢,
    那就需要下麵介紹的第4個知識點了.
    在LJXPerson.h頭文件中做聲明.externconst NSInteger cNumber;
    特別註意,不能再給設置初始值了,它已經在其他文件中(eg:在LJXPerson.m中設置值為100了),我們要清楚extern的作用,表示該常量的數值,是在其他文件中設置的,外部可以直接使用此常量)
    總之:

    eg:在.m中: const NSInteger cNumber =100;
    eg:在.h中: extern const NSInteger cNumber;
  4. 在 .h 中使用 extern 關鍵字聲明該 常量 在其他文件設置值

extern的作用:  extern關鍵字,表示該常量的數值,是在其他文件中設置的,
外部可以直接使用此常量.

註意:在一個項目中,常量不能重名,因此在定義常量時,應該儘量長,有首碼,以保證不會出現重名的情況


本篇主要學習目標回顧:


記憶體五大區域

程式要執行,首先需要被載入到記憶體

1.1 記憶記憶體五大區域的名稱

能夠說出記憶體五大區域的名稱
棧區
堆區
BSS段(靜態區)
數據段(常量區)
代碼段

1.2 記憶棧區/堆區的職責及特點

能夠說出棧區職責(存儲的內容)

  • 局部變數
  • 方法實參

能夠說出棧區的特點
512K
連續
從大到小
速度快
系統管理
能夠說出調用方法時棧區的工作原理
開啟棧幀
保存實參
保存局部變數
方法完成後彈棧,銷毀棧幀,釋放空間
能夠說出堆區的職責(存儲的內容)

  • OC 使用 new 方法創建的對象 由於 ARC 管理機制,OC 程式員通常不需要考慮對象的釋放
  • C 語言使用 malloc 函數分配的空間,需要使用 free 函數釋放

能夠說出堆區的特點
所有程式共用
存儲大數據
程式員管理
不連續
速度沒有棧區快

1.3 記憶全局變數/靜態變數/常量保存的記憶體區域

開發要讓 變化控制在有限的範圍 內

能夠說出教科書中 全局變數 和 靜態變數 的存儲區域

  • 有初始值 的 全局變數 和 靜態變數 保存在 數據段(常量區)
  • 沒有初始值 的 全局變數 和 靜態變數 保存在 BSS 段(靜態區) 當給 全局變數 或 靜態變數 設置初始值後,會被移動到 數據段(常量區)

能夠說出 Xcode 8 中 全局變數 和 靜態變數 的存儲區域

  • 無論是否設置初始值,全局變數 和 靜態變數 都保存在 BSS 段(靜態區) 能夠說出 常量 的存儲區域 常量 存儲在 數據段(常量區) 能夠說出為什麼幾乎不使用 全局變數 開發要讓 變化控制在有限的範圍 內 不能把 全局變數 定義在頭文件中,否則會出現重覆定義 ## 1.4 記憶靜態變數/常量的用法

能夠說出 static 關鍵字的作用

  1. 在 BSS 段為 靜態變數 分配空間
  2. 為 靜態變數 設置初始值,如果沒有指定初始值,會使用 0 來作為初始值
  3. static 關鍵字定義靜態變數的代碼,只會被執行一次!

能夠說出靜態變數的正確用法
* 如果只有一個方法使用,將 靜態變數 定義在方法內部
* 如果有多個方法使用,將 靜態變數 定義在 .m 中
* 不要把靜態變數定義在頭文件中

能夠說出常量的作用

定義一個固定不變的值,全局統一使用,例如公司的網址/電話等...
在 iOS 開發中,通常僅僅在定義 通知字元串 時才會使用到常量

能夠說出常量的正確用法

在 .m 中定義常量並且設置初始值
const NSInteger cNum = 99;
在 .h 中使用 extern 關鍵字聲明常量在其他位置定義並且已經賦值,外部可以直接使用
extern const NSInteger cNum;
常量名應該儘量的長以避免出現重名

結束語

ok! 以上關於記憶體五大區域基礎知識對您起到學習作用了嗎?如果有錯誤之處望指正!謝謝!相關學習共同進步!真心希望其中某個知識點能幫到您!








以上內容目錄結構 (點擊可調轉)

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 該項目主要介紹了二維碼掃描、閃光燈開啟、本地二維碼圖片識別、二維碼生成。分別是zxing和zbar(網格二維碼)分別實現,具體效果運行項目apk... ...
  • 在安卓下實現RTSP流的視頻的播放應該怎麼實現呢? 最近找幾個方法來實現它; 視頻的網路鏈接:rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov 都是需要網路許可權的 1.第一個可以用Android原生的VideoView來實現 佈局文件: 2. ...
  • x寫控制項挺麻煩的,因為有很多細節要處理好,列表控制項使用太頻繁了,網上也各種自定義的方法,一般的listview自定義肯定會聯想到加個頭部,然後監聽事件加動畫,其實方式很多種,今天記錄的方式是另外一種方式,個人覺得復用性更強,寫好了可以通用,思路就是在不動原列表控制項的情況下給它上面套個殼,然後讓殼來操 ...
  • 前言: 自定義控制項的三大方法: onDraw() 裡面是繪製的操作,可以看下其他的文章,下麵來瞭解 onMeasure()和onLayout()方法。 一、onMeasure()、測量 參數即父類傳過來的兩個寬高的"建議值",即把當前view的高設置為:heightMeasureSpec ;寬設置為 ...
  • 最近的項目要用到一個線上報告的下載,於是完成後自己在理一下思路,大體的實現了我要得需求。 話不多說,直接上代碼 首先,取到網路文件的鏈接,進行判段是否需求再次下載還是直接打開 #pragma mark 下載報告 //// 第一步 //是否下載還是打開文件 - (void)downloadPDF:(N ...
  • 1.改變菊花的顏色 // hud.color = [UIColor blackColor]; > hud.bezelView.color =[UIColor blackColor]; 2.改變菊花的坐標 // hud.yOffset=-150; > hud.offset = CGPointMake( ...
  • Xamarin+Prism開發中去PCL類庫,以及導入.net standard類庫的兩種方法介紹與對比。 ...
  • 前言 筆者因為項目需要自定義相機,所以瞭解了一下 Android 關於 camera 這塊的 API。Android SDK 21(LOLLIPOP) 開始已經棄用了之前的 Camera 類,提供了 camera2 相關 API,目前網上關於 camera2 API 介紹的資料比較少,筆者搜集網上資 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...