ios - type - swift4 closure




迅捷管理記憶 (2)

這個問題被清理乾淨,重要的信息轉移到下面的答案。

我對內存管理有一些疑問。

我正在構建一個照片編輯應用程序。 因此,保持低內存使用率非常重要。 此外,我不會發布代碼,因為在執行某項特定操作時,我沒有大量內存洩漏。 我只丟失了幾個KB / MB的所有內容。 通過成千上萬行代碼來查找千字節並不好玩;)

我的應用程序使用核心數據,許多cifilter東西,位置和基礎知識。

我的第一個視圖只是一個tableview,花了我大約5mb的內存。 然後你拍攝一些照片,應用一些過濾器,這會保存到核心數據然後你回到第一個視圖。

是否有可能真正擺脫內存中的所有內容,除了驅動第一個視圖所需的數據。 (非常節省和令人敬畏的5mb)

或者即使你把所有東西都設為零,總會留下一些東西?

獎金問題: UIImageJPEGRepresentationUIImagePNGRepresentation之間的文件大小/ CPU負載是否存在差異? 我知道你可以用JPEG方法設置壓縮質量(在cpu / gpu上更難?)。

只是盡力減少記憶壓力。

更新:

有人向我指出,這個問題可能過於模糊。

我在某些時候遇到的問題如下:

  • 在某些時候,峰值內存使用率太高
  • 導航到第二個視圖控制器並返回導致洩漏
  • 編輯圖像會導致內存洩漏。
  • 將過濾器應用於4-5個以上的圖像會因內存不足而導致崩潰,此時不再有內存洩漏。 (在文書中核實)

這些都是在iPhone 4s上測試的,而不是模擬器。

這裡有一個模因來減輕這個網站的情緒。


這個問題已經開放了很長時間,我現在有足夠的信心回答它。

不同級別的MM:

硬件內存

在Swift with ARC中,我們無法清理實際的硬件RAM。 我們只能讓操作系統為我們做到這一點。 一部分是使用正確的代碼( optionalsweak ),另一部分是為操作系統創造時間來完成它的工作。

想像一下,我們有一個無限期地在所有線程上運行的函數。 它做了一件事,加載圖像,轉換為黑/白並保存。 所有圖像最多只有幾個mb,並且該功能不會產生軟件內存洩漏。 由於圖像沒有設置大小並且可能具有不同的壓縮,因此它們沒有相同的佔用空間。 此功能將始終使您的應用程序崩潰。

此“硬件”內存洩漏是由始終佔用下一個可用內存插槽的功能引起的。

操作系統不介入“實際清理內存”,因為沒有空閒時間。 在每次傳遞之間加一個延遲就完全解決了這個問題。

語言特定的MM

鑄件

某些操作對內存沒有影響,其他操作則:

let myInt : Int = 1
Float(myInt) // this creates a new instance

嘗試投射:

(myInt as Float) // this will not create a new instance.

參考類型與值類型| 類與結構

兩者都有其優點和危險。

結構是內存密集型的,因為它們是值類型 。 這意味著它們在分配給另一個實例時會復制它們的值,從而有效地將內存使 對此沒有任何修復/解決方法。 這就是Structs Structs的作用。

沒有此行為,因為它們是引用類型 。 分配時不會復制。 相反,他們創建對同一對象的 另一個引用ARC自動引用計數是跟踪這些引用的內容。 每個對像都有一個引用計數器。 每次分配時,它都會增加一個。 每次設置對nil的引用,封閉的函數結束,或者封閉的對象取消,計數器就會關閉。

當計數器達到0時,對像被去初始化。

有一種方法可以防止實例取消初始化,從而造成洩漏。 這稱為強參考循環

弱者的好解釋

class MyClass {

    var otherClass : MyOtherClass?

    deinit {
        print("deinit") // never gets called
    }
}

class MyOtherClass {

    var myclass : MyClass?

    deinit {
        print("deinit") // never gets called
    }
}

var classA : MyClass? = MyClass()

// sorry about the force unwrapping, don't do it like this
classA!.otherClass = MyOtherClass()
classA!.otherClass!.myclass = classA // this looks silly but in some form this happens a lot

classA = nil
// neither the MyClass nor the MyOtherClass deinitialised and we no longer have a reference we can acces. Immortalitiy reached they have.

設置一個weak引用

class MyOtherClass {

    weak var myclass : MyClass?

    deinit {
        print("deinit") // gets called
    }
}

進出

函數捕獲傳遞給它們的值。 但也可以將這些值標記為inout。 這允許您更改傳遞給函數的Struct而無需複制Struct。 這可能會節省內存,具體取決於您傳遞的內容以及您在函數中執行的操作。

它也是一種不使用元組而具有多個返回值的好方法。

var myInt : Int = 0

// return with inout
func inoutTest(inout number: Int) {

    number += 5

}

inoutTest(&myInt)
print(myInt) // prints 5

// basic function with return creates a new instance which takes up it's own memory space
func addTest(number:Int) -> Int {

    return number + 5

}

功能編程

國家是時間的價值

函數式編程是面向對象編程的對應部分。 函數式編程使用不可變狀態。

更多關於here

面向對象編程使用具有更改/變異狀態的對象。 舊值不會更新,而是創建新值。

功能編程可以使用更多內存。

FP上的例子

選配

Optionals允許您將thing設置為nil。 這將降低Classes或deinitialise Structs的引用計數。 將事物設置為nil是清理內存的最簡單方法。 這與ARC攜手並進。 一旦將Class的所有引用都設置為nil,它將會釋放並釋放內存。

如果不創建實例作為可選項,則數據將保留在內存中,直到封閉函數結束或封閉類取消。 你可能不知道什麼時候會發生這種情況。 可選項可讓您控制多長時間保持活動狀態。

API MM

許多“內存洩漏”是由具有“清理”功能的框架引起的,您可能沒有調用它。 一個很好的例子是UIGraphicsEndImageContext()在調用此函數之前,Context將保留在內存中。 當創建上下文的函數結束或涉及的圖像設置為nil時,它不會清除。

另一個很好的例子是解僱ViewControllers。 切換到一個VC然後向後移動可能是有意義的,但segue實際上創建了一個VC。 segue back不會破壞VC。 調用dismissViewControllerAnimated()將其從內存中刪除。

閱讀課程參考並仔細檢查沒有“清理”功能。

如果您確實需要儀器來查找洩漏,請查看此問題的其他答案。


點擊Xcode右上角的應用名稱。

單擊彈出菜單中的“編輯方案”。

確保在左側選擇“RUN”,然後單擊窗口頂部附近的“診斷”選項卡。

在'內存管理'標題下檢查'啟用Guard Malloc'

您可能還想嘗試檢查'logging'標題下的'distributed objects'和'malloc stack'

有關防護malloc,防護邊緣和塗鴉的更多信息可以在here找到。



希望這可以幫助!





automatic-ref-counting