Objective-C的對象在內存中是以堆的方式分配空間的,並且堆內存是由你釋放的,即release
棧由編譯器管理自動釋放的,在方法中(函數體)定義的變量通常是在棧內,因此如果你的變量要跨函數的話就需要將其定義為成員變量。
1.棧區(stack):由編譯器自動分配釋放,存放函數的參數值,局部變量等值。其操作方式類似於數據結構中的棧。
2.堆區(heap):一般由程序員分配釋放,若程序員不釋放,則可能會引起內存泄漏。注堆和數據結構中的堆棧不一樣,其類是與鏈表。
操作系統iOS 中應用程序使用的計算機內存不是統一分配空間,運行代碼使用的空間在三個不同的內存區域,分成三個段:“text segment “,“stack segment ”,“heap segment ”。
段“text segment ”是應用程序運行時應用程序代碼存在的內存段。每一個指令,每一個單個函數、過程、方法和執行代碼都存在這個內存段中直到應用程序退出。一般情況下,你不會真的不得不知道這個段的任何事情。
當應用開始以后,函數main() 被調用,一些空間分配在”stack” 中。這是為應用分配的另一個段的內存空間,這是為了函數變量存儲需要而分配的 內存。每一次在應用中調用一個函數,“stack ”的一部分會被分配在”stack” 中,稱之為”frame” 。新函數的本地變量分配在這里。
正如名稱所示,“stack ”是后進先出(LIFO )結構。當函數調用其他的函數時,“stack frame ”會被創建;當其他函數退出后,這個“frame ”會自動被破壞。
“heap” 段也稱為”data” 段,提供一個保存中介貫穿函數的執行過程,全局和靜態變量保存在“heap”中,直到應用退出。
為了訪問你創建在heap 中的數據,你最少要求有一個保存在stack 中的指針,因為你的CPU 通過stack 中的指針訪問heap 中的數據。
你可以認為stack 中的一個指針僅僅是一個整型變量,保存了heap 中特定內存地址的數據。實際上,它有一點點復雜,但這是它的基本結構。
簡而言之,操作系統使用stack 段中的指針值訪問heap 段中的對象。如果stack 對象的指針沒有了,則heap 中的對象就不能訪問。這也是內存泄露的原因。
在iOS 操作系統的stack 段和heap 段中,你都可以創建數據對象。
stack 對象的優點主要有兩點,一是創建速度快,二是管理簡單,它有嚴格的生命周期。
stack 對象的缺點是它不靈活。創建時長度是多大就一直是多 大,創建時是哪個函數創建的,它的owner 就一直是它。不像heap 對象那樣有多個owner ,其實多個owner 等同於引用計數。只有 heap 對象才是采用“引用計數”方法管理它。
stack 對象的創建
只要棧的剩余空間大於stack 對象申請創建的空間,操作系統就會為程序提供這段內存空間,否則將報異常提示棧溢出。
heap 對象的創建
操作系統對於內存heap 段是采用鏈表進行管理的。操作系統有一個記錄空閑內存地址的鏈表,當收到程序的申請時,會遍歷鏈表,尋找第一個空間大於所申請的heap 節點,然后將該節點從空閑節點鏈表中刪除,並將該節點的空間分配給程序。
例如:
NSString 的對象就是stack 中的對象,NSMutableString 的對象就是heap 中的對象。前者創建時分配的內存長度固定且不可修改;后者是分配內存長度是可變的,可有多個owner, 適用於計數管理內存管理模式。
兩類對象的創建方法也不同,前者直接創建“NSString * str1=@"welcome"; “,而后者需要先分配再初始化“ NSMutableString * mstr1=[[NSMutableString alloc] initWithString:@"welcome"]; ”。
ios中堆棧的區別
管理方式:
對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來講,釋放工作有程序員控制,容易產生memory Leak。
申請大小:
棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存區域。這句話的意思是棧頂上的地址和棧的最大容量是系統預先規定好的,在Windows下,棧的大小是2M(也有的說1M,總之是編譯器確定的一個常數),如果申請的空間超過了棧的剩余空間時候,就overflow。因此,能獲得棧的空間較小。
堆:堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閑內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大笑受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
碎片的問題:
對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應,以至於永遠都不可能有一個內存快從棧中彈出。
分配方式:
堆都是動態分配的,沒有靜態分配的堆。棧有兩種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配是有alloc函數進行分配的,但是棧的動態分配和堆是不同的,他的動態分配由編譯器進行釋放,無需我們手工實現。
分配效率:
棧是機器系統提供的數據結構,計算機會在底層堆棧提供支持,分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,他的機制是很復雜的。