首頁 行業 活動 項目 快訊 文娛 時尚 娛樂 科技 汽車 綜合 生活

    減少內存占用最直接的表現是?

    2021-03-19 13:21:46 來源:云加社區

    一、內存優化的必要性

    事實上,因為目前 iPhone 配備的內存越來越高,當內存占用過高時,并不一定會超過系統設定的閾值而引發強殺進程。

    但這并不意味著減少內存占用是沒有意義的,因為當內存占用過高時,很容易引起一系列的副作用。最直接的表現是 App Crash,當然還有很多更為深遠的副作用。

    1. FOOM

    FOOM 是最直接的影響了,當內存占用過多導致整個系統的可用內存不足時,App所在的進程容易被殺掉。而且相比于一般的 Crash 來說,FOOM 更難以檢測,并且也更難排查。

    2. 限制并發數量

    如果一個任務占用了過多的內存,但總的內存是有限的,那么任務的并發數將會受到直接限制。表現上就是 App 里某個功能可同時執行的數量有限,或者可以同時顯示的內容有數量限制。

    同時,因為內存是有限資源,當占用內存過多時,會容易導致操作系統殺掉其它 App 的進程來給當前的 App 提供足夠的內存空間,這對用戶體驗是不利的。

    3. 增加耗電

    由于 iOS 系統的 Memory Compressor 的存在,當可用內存不足時,一部分 Dirty Page 會被壓縮存儲到磁盤中,當用到這部分內存時,再從磁盤里加載回來。這會造成 CPU 花費更多的時間來等待 IO, 間接提高 CPU 占用率,造成耗電。

    二、原因分析

    1. 圖片顯示原理

    圖片其實是由很多個像素點組成的,每個像素點描述了該點的顏色信息。這樣的數據是可以被直接渲染在屏幕上的,稱之為 Image Buffer。

    事實上,由于圖片源文件占用的存儲空間非常大,一般在存儲時候都會進行壓縮,非常常見的就是 JPEG 和 PNG 算法壓縮的圖片。

    因此當圖片存儲在硬盤中的時候,它是經過壓縮后的數據。經過解碼后的數據才能用于渲染,因此需要將圖片顯示在屏幕上的話,需要先經過解碼。解碼后的數據就是 Image Buffer 。

    當圖片顯示在屏幕上時,會復制顯示區域的Image Buffer去進行渲染。

    2. 圖片真實占用內存

    對于一張正在顯示在屏幕上的,尺寸為 1920*1080 的圖片來說,如果采用 SRGB 的格式(每個像素點的顏色由 red,green,blue,alpha 一個共 4 個 bytes 來決定)的話,那么它占用的內存為:

    也就是說,一張非常普通的圖片,解碼后占用的內存就是 7.9 MB,這是非常夸張的。而圖片顯示時所占的內存大小是與尺寸和顏色空間正相關的,與壓縮算法、圖片格式、圖片文件的大小沒有關聯。

    三、解決方式

    1. 避免將圖片放在內存里

    對于不顯示在屏幕上的圖片,在絕大部分時間里,其實是沒有必要放在內存里的。解碼后的 UIImage 是非常大的,對于不需要顯示的圖片是不需要解碼的。而對于不顯示在屏幕上的圖片,一般也沒有必要繼續持有著 UIImage 對象。

    2.圖片縮放

    圖片縮放是很常見的處理方式,一般來說,常見的思想可能是重新畫一張小一點的圖片,往往是用 UIGraphicsBeginImageContextWithOptions的方式:

    這種方式存在以下問題:

    第一,默認是 SRGB 的格式,也就是說每個像素需要占4個bytes的空間,對于一些黑白或者僅有alpha通道的數據來說是沒有必要的。

    第二,需要將原圖片完全解碼后渲染出來,原圖片的解碼會造成內存占用的高峰。

    對于問題一的解決,可以使用新的 UIGraphicsImageRenderer 的方式,這種情況下框架會自動幫你選擇對應的顏色格式,減少不必要的消耗。

    這種方式在一定的場景有所優化,但是沒有解決問題二中存在的內存峰值的問題。由于處理前的圖片并不一定展示在屏幕上,解碼后的數據是冗余信息,因此應該避免圖片的解碼。

    對于峰值過高的問題,最直接的思想是采用流式的方式進行處理。而底層的 ImageIO 的接口就采用了這種方式:

    3. 降低峰值

    通過 ARC 管理內存的對象,注冊在某個 Autoreleasepool 中,Autoreleasepool 在 drain 的時候釋放已經沒有使用的對象。

    一般沒有進行特殊處理的話,會在 Runloop 結束后,有一次 Autoreleasepool 的 drain 操作,而這次 Runloop 中生成的對象也是由這個 Autoreleasepool 來管理的。這部分的原理有很多的文章介紹,這里就不多贅述了。

    在圖片批量處理的過程中,由于還在一個 Runloop 里,此時引用計數為 0 的對象是不會被釋放的。因此需要在每次循環后觸發 Autoreleasepool 的 drain 操作:

    4. 裁剪顯示的圖片

    在很多場景下,圖片是不會完整的顯示出來的,例如下圖所示的情況:

    在這種情況中,即使給 UIImageView 一張完整的圖片,最后渲染的時候也只會截取顯示區域的 Image Buffer 去進行渲染。

    這就意味著,區域外的數據,其實是沒有必要的。因此在這種場景下,其實只需要裁減顯示區域的圖片即可。

    舉個例子,以前面提到 1920 * 1080 的圖片為例, 顯示時需要占用的內存為 829440 bytes。如果它是以 ScaleAspectFill 的方式放置在一個 300 x 300 的 UIImageView 中時,那么其實一張 300 x 300 的圖片就足以展示,而此時這張圖片占用的內存為 360000 bytes, 僅為前者的 43% 。

    關鍵詞: 減少內存占用的

    上一篇:鍵盤上怎么打出頓號?

    下一篇:電腦聲音與卸載聲卡驅動有關嗎?

    責任編輯:

    最近更新

    點擊排行
    推薦閱讀

    亚洲精品无码专区久久久| 亚洲第一黄色网址| 久久国产亚洲电影天堂| 亚洲中文字幕无码久久综合网| 亚洲国产精品一区二区九九| 亚洲国产成人VA在线观看| 处破女第一次亚洲18分钟| 色窝窝亚洲av网| 亚洲?V无码乱码国产精品| 亚洲国产成人久久笫一页| 亚洲伦乱亚洲h视频| 亚洲色偷拍区另类无码专区| 国产亚洲精品资在线| 亚洲一区日韩高清中文字幕亚洲 | 亚洲欧洲日产国码在线观看| 亚洲精品国产手机| 亚洲一区二区三区高清视频| 亚洲av永久综合在线观看尤物| 亚洲欧美日韩一区二区三区在线| 亚洲无码一区二区三区 | 亚洲精品国产自在久久| 久久亚洲2019中文字幕| 亚洲国产综合无码一区| 亚洲av无码国产精品色午夜字幕| 婷婷亚洲久悠悠色悠在线播放 | AV激情亚洲男人的天堂国语| 亚洲av中文无码| 国产亚洲色视频在线| 亚洲AV无码一区东京热| 久久久久亚洲AV无码网站| 亚洲啪啪免费视频| 亚洲妇女无套内射精| 亚洲国产专区一区| 亚洲国产精品成人久久 | 亚洲AⅤ永久无码精品AA| 国产偷国产偷亚洲清高动态图| 亚洲av午夜福利精品一区| 亚洲精品在线免费看| 亚洲色大成网站www永久男同 | 国产精品亚洲专区一区| 国产黄色一级毛片亚洲黄片大全|