小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

先弄清楚這里的學(xué)問,再來談iOS內(nèi)存管理與優(yōu)化(二)

 jlland 2016-03-07




上篇文章講述了iOS內(nèi)存管理的基本概念,這里是一些內(nèi)存優(yōu)化的小技巧

Strong Weak Dance

這個大家都知道,就是處理循環(huán)引用,合理使用weakunowned。

降低內(nèi)存峰值

Lazy Allocation

延時加載是很常用的一種優(yōu)化方法,如果有些情況我們不會立即使用某一對象和某些資源,我們完全可以在使用的時候再進(jìn)行加載,這些就可以避免初次運(yùn)行程序的時候內(nèi)存消耗嚴(yán)重。

lazy var goodsImageView: UIImageView = {
        let goodsImageView = UIImageView()
        return goodsImageView
    }()

在喵神的博客中,也發(fā)現(xiàn)了很好玩的地方,Swift標(biāo)準(zhǔn)庫中,定義了一些Lazy方法,可以配合像 map或是 filter 這類接受閉包并進(jìn)行運(yùn)行的方法一起,讓整個行為變成延時進(jìn)行。

let data = 1...3
let result = data.lazy.map {
    (i: Int) -> Int in
    print('正在處理 \(i)')
    return i * 2
}

print('準(zhǔn)備訪問結(jié)果')
for i in result {
    print('操作后結(jié)果為 \(i)')
}

print('操作完畢')

運(yùn)行結(jié)果為:

// 準(zhǔn)備訪問結(jié)果
// 正在處理 1
// 操作后結(jié)果為 2
// 正在處理 2
// 操作后結(jié)果為 4
// 正在處理 3
// 操作后結(jié)果為 6
// 操作完畢

圖片的讀取

相信寫代碼的時候都會涉及到圖片的讀取,我們經(jīng)常使用的方法

imageView?.image = UIImage(named: name)
imageView?.image = UIImage(contentsOfFile: path)
  • 對于第一種,是帶緩存機(jī)制的,如果頻繁讀取小文件,用它就只需要讀取一次就好,但是缺點(diǎn)就是如果使用大圖片會常駐內(nèi)存,對于降低內(nèi)存峰值是不利的。

  • 對于第二種方法,不帶緩存機(jī)制,適合使用大圖片,使用完就釋放

NSData & 內(nèi)存映射文件

在我們經(jīng)常使用NSData時,出鏡率很高的兩個方法

public init?(contentsOfFile path: String)
public init(contentsOfFile path: String, options readOptionsMask: NSDataReadingOptions) throws

第二種比第一個多一個Options,第二種方式是創(chuàng)建了一個內(nèi)存映射文件,把內(nèi)容放在虛擬內(nèi)存中,只有讀取操作的時候才會讀到相對應(yīng)頁的物理內(nèi)存頁中。所以后者,對于大文件是很劃算的,推薦使用第二種。對于可選的方式如下:


其他方式

在莊延軍老師的分享中,還有其他一些技巧,但是對于只懂Swift的我,實(shí)在沒接觸過哪些方案,等我接觸之后,再來寫第三個分享。下面簡單列舉一下:

  • calloc VS malloc memset

  • 棧內(nèi)存分配

NSAutoReleasePool

MRC時代說起,當(dāng)需要我們手動來管理對象引用計數(shù)的時候,我們需要RetainRelease方法,那么可能一個線程中有大量的RetainRelease方法,這個時候使用一個池一起管理他們是不是方便很多,將線程中要執(zhí)行的任務(wù)都放在自動釋放池中,自動釋放池會捕獲所有任務(wù)中的對象,在任務(wù)結(jié)束或線程關(guān)閉之時自動釋放這些對象。

當(dāng)然自動釋放池都會使用NSAutoreleasePool類創(chuàng)建,并在自動釋放池收到 drain消息時將這些對象的引用計數(shù)減一,然后將它們從池子中移除 (這一過程形象地稱為“抽干池子”)。

ARC時代,不再使用NSAutoreleasePool來創(chuàng)建自動釋放池,而是使用@autoreleasepool代碼塊,新建Objective-C工程的時候,會幫我們創(chuàng)建一個main.m文件,已經(jīng)幫我們在主線程創(chuàng)建了一個自動釋放池。

int main(int argc, char * argv[]) {
@autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}

}

更進(jìn)一步,其實(shí)@autoreleasepool 在編譯時會被展開為 NSAutoreleasePool,并且在每個主Runloop結(jié)束時進(jìn)行drain操作。

那么到了Swift時代,又具有了新的變化,不需要手動地調(diào)用autorelease 這樣的方法來管理引用計數(shù),但是這些方法還是都會被調(diào)用的,只不過是編譯器在編譯時在合適的地方幫我們加入了而已。

在Swift標(biāo)準(zhǔn)庫中可以發(fā)現(xiàn):

public func autoreleasepool(@noescape code: () -> ())

那么我們就可以利用閉包的特點(diǎn),在需要的時候非常簡便的使用它

autoreleasepool { 
    // 線程執(zhí)行任務(wù)的邏輯代碼
}

AutoReleasePool

為什么在ARC時代還需要使用自動釋放池呢?其原因就是為了避免內(nèi)存峰值,那比如說我有一個很大的For循環(huán),里面不斷讀入較大的文件。其實(shí)每迭代一次,資源都已經(jīng)用完了(就是說我用好了,還你),不需要再用了,這個時候就可以釋放了,但是程序需要等到Runloop結(jié)束的時候才可以釋放,這就增大了內(nèi)存的峰值。

上面的話有點(diǎn)繞,但是真心非常重要。

那么怎么做,可以減小內(nèi)存峰值呢?我們可以在For循環(huán)中添加autoreleasepool,這樣就可以保證每次迭代完畢一次就可以釋放點(diǎn)內(nèi)存。

func loadBigData() {
    for i in 1...10000 {
        autoreleasepool {
            let data = NSData.dataWithContentsOfFile(
                path, options: nil, error: nil)
        }
    }
}

簡單總結(jié)

上面的闡述了多種方法,其中對于降低內(nèi)存峰值有作用的是:

  • Lazy Allocation

  • 圖片的讀取的正確方式

  • NSData & 內(nèi)存映射文件

  • callocVS malloc memset

  • 棧內(nèi)存分配

  • autoReleasePool

內(nèi)存警告處理

到收到內(nèi)存警告的時候,所要做的:

  • 盡可能多的釋放資源,尤其是圖片等占用內(nèi)存多的資源,等需要的時候再進(jìn)行重建

  • 單例模式的濫用,會導(dǎo)致單例對象一直持有資源,在內(nèi)存緊張的時候要進(jìn)行釋放,當(dāng)然我也在其他博客中看到一些單例模式的替換方案

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多