iOS中的堆(heap)和棧(stack)的理解,iosheap
作業系統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"]; ”。
(miki西遊 @mikixiyou 原文連結: http://mikixiyou.iteye.com/blog/1595230 )
再補充一點,這裡說的是作業系統的堆和棧。
在我們學習“資料結構”時,接觸到的堆和棧的概念和這個作業系統中的堆和棧不是一回事的。
作業系統的堆和棧是指對記憶體進行操作和管理的一些方式。
“資料結構“的堆實際上指的就是(滿足堆性質的)優先Queue 的一種資料結構,第1 個元素有最高的優先權;棧實際上就是滿足先進後出的性質的資料或資料結構。
堆(heap)與棧(Stack)的不同是什?為何平時都把堆棧放在一起講?
程式的運行場所是記憶體,棧和堆是進程的虛擬記憶體中的兩部分地區。
當程式被執行時,程式碼,你所建立的變數、常量等都會被壓入棧空間裡,棧是程式碼的執列區域。棧的記憶體位址是連續的且被一一記錄,所以說當你建立了一個變數(比如int var = 1),我們就可以通過var這個變數來訪問變數的內容。在這裡,var就存放在棧中,它的地址已經預設被編譯器計算好了,調用過程也不需要你涉及到有關地址的操作。更直觀的感受是數組,數組裡的元素在棧裡面是連續排放的,相鄰兩個元素的地址相差1。
而堆是不同於棧的另一部分地區,系統會給每個程式分配一部分棧空間讓他們能夠運行起來,問題就是棧空間必然存在不夠用的問題,而堆不屬於程式,堆是獨立的,是公用的。只要你malloc(sizeof(SIZE_YOU_WANT)),就可以得到相應一部分的堆空間。
有棧,為什麼用堆?
::棧裡面的東西有生命週期,說俗點就是變數範圍,你在函數內部建立一個變數,函數調用結束這個變數就沒了。而堆裡面的東西獨立於你的程式,malloc()之後,除非你free()掉,否則一直存在。
為什麼用堆少?
::麻煩!
有什麼要注意?
::堆裡面申請的東西,是隨機分配的,不像棧裡面的地址都已經計算好了。所以申請了堆空間之後一定要建立一個指標儲存你說申請到的堆空間的地址。不然就找不到你申請的空間了。
既然涉及到指標,請注意用之前檢查一下指標空不空的問題。
堆空間的東西申請好,在用完之後一定要free()掉,以防止堆溢出。
說到安全性,還真是挺麻煩的。(純手打)
跪堆(heap)與堆棧(stack)有什不同
什麼是堆棧在電腦領域,堆棧是一個不容忽視的概念,但是很多人甚至是電腦專業的人也沒有明確堆棧其實是兩種資料結構。要點:堆:順序隨意棧:先進後出堆和棧的區別隊列:先進先出,後進後出. 堆棧:先進後出,後進先出.一、預備知識—程式的記憶體配置 一個由c/C++編譯的程式佔用的記憶體分為以下幾個部分 1、棧區(stack)— 由編譯器自動分配釋放 ,存放函數的參數值,局部變數的值等。其操作方式類似於資料結構中的棧。 2、堆區(heap) — 一般由程式員分配釋放, 若程式員不釋放,程式結束時可能由OS回收 。注意它與資料結構中的堆是兩回事,分配方式倒是類似於鏈表。 3、全域區(靜態區)(static)—,全域變數和靜態變數的儲存是放在一塊的,初始化的全域變數和靜態變數在一塊地區, 未初始化的全域變數和未初始化的靜態變數在相鄰的另一塊地區。 - 程式結束後由系統釋放。4、文字常量區 —常量字串就是放在這裡的。 程式結束後由系統釋放 。5、程式碼區—存放函數體的二進位代碼。 二、例子程式 這是一個前輩寫的,非常詳細 //main.cpp int a = 0; 全域初始化區 char *p1; 全域未初始化區 main() 分配得來得10和20位元組的地區就在堆區。 strcpy(p1, "123456"); 123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"最佳化成一個地方。