從堆疊剖析block為什麼用copy

2021-07-10 22:00:14 字數 1615 閱讀 4972

1.首先理解連個概念

堆:heap ->

heap的空間需要手動分配。

heap

與動態記憶體分配相關

,記憶體可以隨時在堆中分配和銷毀。我們需要明確請求記憶體分配與記憶體銷毀。

簡單來說,就是malloc與free.

棧:stack-> 

stack的空間由作業系統進行分配。

在現代作業系統中

,乙個執行緒會分配乙個

stack.

當乙個函式被呼叫,乙個stack frame(棧幀)就會被壓到stack裡。裡面包含這個函式涉及的引數,區域性變數,返回位址等相關資訊。當函式返回後,這個棧幀就會被銷毀。而這一切都是自動的,由系統幫我們進行分配與銷毀。對於程式設計師是透明的,我們不需要手動排程

所有的oc物件都是分配在heap中的,乙個物件在alloc的時候就已經分配好了記憶體空間  

stack物件通常有速度的優勢,而且不會發生記憶體洩露問題。那麼為什麼oc的物件都是分配在heap的呢?

原因在於:

1. stack物件的生命週期所導致的問題。例如一旦函式返回,則所在的stack frame就會被摧毀。那麼此時返回的物件也會一併摧毀。這個時候我們去retain這個物件是無效的。因為整個stack frame都已經被摧毀了。簡單而言,就是stack物件的生命週期不適合objective-c的引用計數記憶體管理方法。

2. stack物件不夠靈活,不具備足夠的擴充套件性。建立時長度已經是固定的,而stack物件的擁有者也就是所在的stack frame

現在就是block的問題,在以前用block修飾的時候一直用strong 檢視資料和很多源**時發現都是用的copy  雖說沒有什麼錯誤但總歸是不知道為什麼這樣,首先block在oc中有三中型別:

1.全域性靜態block不會訪問任何外部靜態變數:這種不捕捉外界變數的block是不需要記憶體管理的,這種block不存在於heap或是stack而是作為**片段存在,類似於c函式

2.儲存在棧中的block,但函式返回時被銷毀:這就是這次探索的重點了,需要涉及到外界變數的block在建立的時候是在stack上面分配空間的,也就是一旦所在函式返回,則會被摧毀。這就導致記憶體管理的問題,如果我們希望儲存這個block或者是返回它,如果沒有做進一步的copy處理,則必然會出現問題

3.儲存在堆中的block,當引用計數未0時會被銷毀:因此為了解決block作為stack object的這個問題,我們最終需要把它拷貝到堆上面來。而此時nsconcretemallocblock扮演的就是這個角色。拷貝到堆後,block的生命週期就與一般的oc物件一樣了,我們通過引用計數來對其進行記憶體管理。

真正的答案:

因此答案便是因為block在建立時是stack物件,如果我們需要在離開當前函式仍能夠使用我們建立的block。我們就需要把它拷貝到堆上以便進行以引用計數為基礎的記憶體管理

也就是說arc幫助我們完成了copy的工作,在arc下,即使你宣告的修飾符是strong,實際上效果是與宣告為copy一樣的。因此在

arc情況下

,建立的

block

仍然是nsconcretestackblock型別,

只不過當

block

被引用或返回時

,arc

幫助我們完成了

copy

和記憶體管理的工作

Block為什麼用copy修飾

預設情況下,block是存檔在棧中,可能被隨時 通過copy操作可以使其在堆中保留乙份,相當於一直強引用著,因此如果block中用到self時,需要將其弱化,通過 weak或者 unsafe unretained.以下是示例 及其說明,讀者可以試著列印出不同情況下block的記憶體情況 viewco...

iOS之Block為什麼用copy修飾

在通讀文章之前,您可能需要了解記憶體分配的基礎知識。預設情況下,block是存檔在棧中,可能被隨時 通過copy操作可以使其在堆中保留乙份,相當於一直強引用著,因此如果block中用到self時,需要將其弱化,通過 weak或者 unsafe unretained.以下是示例 及其說明,讀者可以試著...

python為什麼用flask 為什麼用flask

flask是python在web開發領域乙個輕量級的框架,為什麼選擇flask呢?此文可能會給你答案。選擇flask的原因 1.微框架 簡潔 只做它需要做的,給開發展提供了很大的擴充套件性。2.flask和相關的依賴 jinja2 werkzeug 設計得非常優秀,用著簡單。3.開發效率非常高,比如...