Swift 記憶體安全

2021-08-20 21:11:54 字數 3501 閱讀 7615

//1. 訪問記憶體衝突

//對同一塊記憶體的讀寫同時進行

//2. 記憶體訪問特徵

//按衝突訪問的語境, 記憶體訪問有三個特徵: 訪問是否是讀或寫, 訪問的中間過程, 記憶體正在被訪問

//特別地, 當兩個訪問滿足以下條件時, 衝突發生:

//至少乙個寫

//訪問記憶體的同乙個位址

//durations 交叉

//讀和寫的區別: 寫改變記憶體位址, 讀不會改變.

//記憶體訪問的 duration 要麼是 instantaneous ,要麼是 long-term

//乙個訪問是 instantaneous 如果在訪問期間其它**不能執行, 因此兩個 instantaneous 訪問不能同時發生, 大多數記憶體訪問都是 instantaneous

func onemore(than number: int) -> int

var mynumber = 1

mynumber = onemore(than: mynumber)

print(mynumber)

// prints "2"

//乙個訪問是 long-term 如果在它訪問開始到訪問結束之前其它**可以執行, 叫做 overlap, 乙個 long-term 訪問可以和其它 long-term 訪問或 instantaneous 訪問 overlap

//overlap 訪問主要發生使用 in-out 引數的函式或方法的**中, 或者結構體的 mutating 方法**中

//3. in-out 引數的衝突訪問

//乙個函式對於所有它的 in-out 引數是 long-term 訪問, 對乙個 in-out 引數的寫訪問在所有的非 in-out 引數被 evaluated 後開始, 並在函式呼叫期間一直持續.如果有多個 in-out 引數, 寫訪問的順序按照引數的順序

//這種 long-term 的寫訪問的後果是你不能訪問被傳遞做為 in-out 引數的原始變數, 即使 scoping rules 和 訪問控制允許, 任何對原始變數的訪問會造成衝突:

var stepsize = 1

func incrementinplace(_ number: inout int)

incrementinplace(&stepsize)

// error: conflicting accesses to stepsize

//number += stepsize, 對 stepsize 是寫

//_ number: inout int, 對 stepsize 是讀

//讀寫訪問同乙個記憶體位址, 並且 overlap, 所以發生衝突

//解決辦法之一是複製乙個 stepsize

var copyofstepsize = stepsize

incrementinplace(©ofstepsize)

// update the original.

stepsize = copyofstepsize

// stepsize is now 2

//讀訪問在寫訪問開始之前結束, 不會發生衝突

//對 in-out 引數 long-term 寫訪問的另乙個後果是, 傳遞同乙個變數給有多個 in-out 引數的函式, 會發生衝突

func balance(_ x: inout int, _ y: inout int)

var playeronescore = 42

var playertwoscore = 30

balance(&playeronescore, &playertwoscore) // ok

// balance(&playeronescore, &playeronescore)

//對同乙個記憶體同時進行讀訪問, 發生衝突

//4. 方法中對 self 的衝突訪問

//乙個struct 的 mutating 方法在方法呼叫期間可以對 self 進行寫訪問.

struct player

}// restorehealth 方法對 self 的寫訪問在方法呼叫期間一直持續, 沒有其它**對 player 例項的屬性 overlap 訪問, 下邊的 sharehealth 方法, 用另乙個 player 例項作為 in-out引數, 提供了 overlap 訪問的可能

// extension player

// }

//// var oscar = player(name: "oscar", health: 10, energy: 10)

// var maria = player(name: "maria", health: 5, energy: 10)

// oscar.sharehealth(with: &maria) // ok: 對 oscar, maria 的讀訪問,訪問 overlap 但是訪問的記憶體位址不同

// oscar.sharehealth(with: &oscar) // error: 對 oscar 同時進行連個讀訪問

// 5. 屬性的衝突訪問

//struct, tuple, enum 等值型別是由個體元素組成, 例如結構體的屬性, 元組的元素.因為它們是值型別, 對其中任何乙個值的改變都會改變整個值, 意味著讀寫乙個屬性要讀寫整個值.例如對乙個元組元素的 overlap 寫訪問會產生衝突:

var playerinformation = (health: 10, energy: 20)

balance(&playerinformation.health, &playerinformation.energy)

// error: conflicting access to properties of playerinformation

//在函式呼叫期間, 元組兩個元素作為 in-out 引數傳入 balance 方法, 同時對整個元組進行寫訪問, 產生衝突

//holly 為全域性變數

var holly = player(name: "holly", health: 10, energy: 10)

balance(&holly.health, &holly.energy) // error

//player 值型別, 同上類似

//實際上, 大多數對 struct 的 overlap 訪問是安全的.例如把上邊的 holly 變數變為乙個區域性的變數

func somefunction()

somefunction()

//排他訪問(exclusive access)是比 memory safety 更嚴格的要求, swift 允許這種 memory-safe 的**, 如果編譯器證明這類 nonexclusive access 是安全的.

//特別地,如果下列條件滿足, 編譯器可以證明對乙個 struct 屬性的訪問是安全的:

//只訪問了儲存屬性, 而沒有訪問計算屬性或型別屬性

//struct 是乙個區域性變數, 不是全域性變數

//struct 沒有被乙個閉包捕獲,或者被非逃逸閉包捕獲

Swift 記憶體安全

swift 也保證同時訪問同一塊記憶體時不會衝突,通過約束 裡對於儲存位址的寫操作,去獲取那一塊記憶體的訪問獨占權。因為 swift 自動管理記憶體,所以大部分時候你完全不需要考慮記憶體訪問的事情。然而,理解潛在的衝突也是很重要的,可以避免你寫出訪問衝突的 如果你的 確實存在衝突,那在編譯時或者執行...

swift 記憶體管理

不管在什麼語言裡,記憶體管理的內容都很重要,所以我打算花上比其他 tip 長一些的篇幅仔細地說說這塊內容。swift 是自動管理記憶體的,這也就是說,我們不再需要操心記憶體的申請和分配。當我們通過初始化建立乙個物件時,swift 會替我們管理和分配記憶體。而釋放的原則遵循了自動引用計數 arc 的規...

Swift 記憶體管理

1 object c 經歷兩個階段 1 手動引用計數記憶體管理 manual reference counting,mrc 2 自動引用計數記憶體管理 automatic refernce counting,arc 2 引用型別 記憶體分配到 堆 上,需要人為管理。值型別 記憶體分配到 棧 上,有處...