導航:首頁 > 操作系統 > androidarraymap遍歷

androidarraymap遍歷

發布時間:2024-10-28 00:16:42

1. 性能優化-內存優化

雖然Android有有優秀的內存管理機制,內存釋放有垃圾收集器(GC)來回收。但內存的不合理使用還是會造成一系列的性能問題,比如短時間分配大量內存對象、內存泄漏等問題。本篇講述如何檢測內存問題和解決,希望在內存優化方面能夠提供一些幫助。

首先學習Android內存管理機制,了解系統如何分配和回收內存。

Java對象在虛擬機上運行有7個階段,也就是對象的生命周期

注意:在創建對象後,在確定不再需要使用該對象時,使對象置空,這樣更符合垃圾回收標准,比如Object = null,可以提供內存使用效率。

在Android系統中,堆實際上是一塊匿名共享內存,Android虛擬機並沒有直接管理這塊匿名共享內存,而是把它封裝成一個mSpace,由底層C庫來管理。

為了整個系統的內存控制需要,在Android系統為每一個應用程序都設置一個硬性的Dalvik Heap Size最大限制閾值(視設備而定)。如果應用佔用內存空間接近閾值時,再嘗試分配內存很容易OOM。Android系統的內存堆被劃分為不同的區塊,根據對數據配置對類型分配不同的區域內存,垃圾回收時,也會根據這些配置執行不同的垃圾回收處理過程,並且每一個區塊都有指定的單位大小。

Android Rumtime有兩種虛擬機,Dalvik和ART,他們分配的內存區域塊是不同的:

其中Image Alloc和Zygote Alloc在Zygote進程和應用程序進程之間共享,而Allocation Space是每個進程都獨立擁有一份。但Image Space的對象只創建一次,而Zygote Space的對象需要在系統每次啟動時,根據運行情況都重新創建一遍。

整個內存分為三個區域:年輕代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。

年輕代分為三個區,一個Eden區和兩個Survivor區S0和S1(S0和S1隻是為了好區分,兩者實質一樣,角色可互換)。

年老代存放的是上面年輕代復制過來的對象,也就是在年輕代還存活的對象並且區滿了復制過來的。一般來說,年老點中的對象生命周期都比較長。

用於存放靜態的類和方法,以及年老代移動過來的對象。持久代對垃圾回收沒有顯著影響。

內存對象的處理過程如下

回收機制

系統在Young Generation和Old Generation上採用不同的回收機制。每一個Generation的內存區域都有固定的大小。隨著對象陸續被分配到此區域,當對象總的大小臨近這一級別內存區域的閾值時,會觸發GC操作,以便騰出空間來存放其他新的對象。

詳細內容可參考我另一篇 文章

Android系統中,GC有以下三種類型:

在GC過程中,任何其他在工作的線程(包括負責繪制的線程)都可能會被暫停,一旦GC消耗的時間超過16ms的閾值,就會出現丟幀。也就是說 頻繁的GC會增加應用的卡頓

如果內存在某以階段的峰值達到了內存空間的閾值,或者頻繁地發生內存峰值(毛刺現象),剛好在這個峰值時,需要申請一塊較大的內存,就會由於對 內存空間不足而導致OOM異常

內存泄漏是指應用已經不會再使用的內存對象,但垃圾回收時沒有把這些辨認出來,不能及時地回收,仍然一直保留在內存中,佔用了一定的空間,並且最終會到GC耗時最長的Old Generation,不釋放給其他對象。

內存優化主要有以下幾個意義:

Memory Monitor是一款使用非常簡單的圖形化工具,可以很好地監控系統或應用的內存使用情況。可以快速發現內存抖動、大內存分配,甚至由於GC導致的卡頓。

(AS3.0以上的Android Profiler)

Heap Viewer的主要功能是查看不同數據類型在內存中的使用情況。通過分析這些

Allocation Tracker可以分配跟蹤記錄應用程序的內存分配,並列出了他們的調用堆棧,可以查看所有對象內存分配的周期。

可以先用Memory Monitor或者Heap Viewer找到內存異常的場景,然後使用Allocation Tracker分析這個場景的內存使用情況。

GC會選擇一些還存活的對象作為內存遍歷的根節點GC Roots,通過對GC Roots對可達性來判斷是否需要回收。GC Roots是系統選擇的對象根節點,對Heap進行遍歷,沒有被直接或間接遍歷到的引用會被GC 回收,能遍歷到的能被回收。這類在當前應用周期內不再使用的對象被GC Roots引用,導致不能回收,使實際可使用內存變小,這種現象在Android應用中稱為內存泄漏。

MAT是一個快速、功能豐富的Java heap分析工具,可以幫助開發者定位導致內存泄漏的對象,以發現大的內存對象,然後解決內存泄漏並優化。

分析內存最常用的是Histogram和Dominator Tree兩個視圖

(具體使用自行搜索哈哈)

上例中靜態實例mTestMole會一直持有該Activity的引用,導致Activity的內存資源不能正常回收。

如果setup(Context context)傳入的是Activity的Context,使得Activity被一個單例持有,mAppSettings作為靜態變數,生命周期大於Activity,產生內存泄漏。

LeakCanary是一個檢測內存的開源類庫,可以在發生內存泄漏時告警,並且生成leak trace分析泄漏位置,同時可以提供Dump文件。

LeakCanary.install(this)會安裝一個Leaks的Apk,同時也啟用一個ActivityRefWatcher,用於自動監控調用Activity.onDestroy()之後泄漏的對象。

默認情況下,只對Activity進行監控,如果需要對Fragment或Service等這類組件監控,可以在Fragment onDestroy方法中,或自定義組件的周期結束回調介面加入以下實現

僅僅依靠默認的處理方式,體驗不是很好,可以自定義監控結果處理。

heapDump:堆內存文件,可以拿到完成的hprof文件

result:監控到內存的狀態,如是否泄漏等

leakInfo:leak trace詳細信息

根據業務需求,使用合適的引用類型

考慮上面的情況,在自動裝箱轉化時,都會產生一個新的對象,這些對象比基礎數據類型要大,這樣會產生更多內存和性能開銷。(int只有4位元組,而Integer對象有16位元組)

HashMap是一個 散列鏈表 ,先HashMap中put元素時,先根據key的HashCode重新計算hash值,根據hash值得到這個元素在數組中的位置,如果數組位置上已經存放有其他元素了,那麼在這個位置上的元素將以鏈表的形式存放,新加入的放在鏈頭。為了減少hash沖突,會配置一個大的數組,從內存節省的角度是非常不理想的。為了解決這個問題,Android提供了一個替代容器ArrayMap。

ArrayMap提供了和HashMap一樣的功能,但避免了過多的內存開銷,方法是使用兩個小數組而不是一個大數組。其中一個數組記錄對象Key Hash過後的順序列表,另外一個數組按Key的順序記錄Key-Value值,根據Key數組的順序,交織在一起。在獲取某個value時,ArrayMap會計算輸入Key轉換後的hash值,然後使用二分查找法對Hash數組尋找到對應的index,然後通過這個index在另外一個數組中直接訪問需要的鍵值對。如果在第二個數組鍵值對中的key和前面輸入的查詢key不一致,就認為發生了碰撞沖突。ArrayMap會以該key為中心點,分別上下展開,逐個對比查找,直到找到匹配的值。

ArrayMap中執行插入或刪除時,性能比HashMap要差一點,但如果設計對象數少,比如1000以下,不用擔心這個問題。用ArrayMap能節省內存。

枚舉的優點是類型安全,可讀性高,但是枚舉的內存開銷是直接定義常量的三倍以上。官方也提醒盡量避免使用枚舉類型,同時提供註解的方式檢測類型安全,目前提供了int和String兩者類型註解方式:IntDef和StringDef。即使用「常量定義+註解」替代枚舉。

使用IntDef和StringDef需要在Gradle引入依賴

Android設備上顯示圖片需要把圖片解碼成點陣圖格式,佔用的內存只和點陣圖的質量和大小相關。下面介紹幾種減少圖片內存開銷的方法:

系統默認點陣圖格式是RGB_8888佔用內存較高,一般用RGB_565或RGB_4444代替。
RGB_8888佔32bit、GB_565和RGB_4444都是16bit、ALPHA_8佔8bit

如果內存中的圖片大於屏幕需顯示圖片的大小,這些高解析度圖片會導致性能問題。可以通過重置這些圖片大小,讓它們符合實際顯示大小。Bitmap的inSampleSize屬性能實現點陣圖縮放功能。

可參考 郭霖博客

本文參考書籍《Android應用性能優化最佳實踐》

閱讀全文

與androidarraymap遍歷相關的資料

熱點內容
程序員搬運 瀏覽:63
手機app的視頻存在哪裡了 瀏覽:280
程序員幾年會淘汰 瀏覽:739
調試助手查詢sim卡命令 瀏覽:441
催眠程序員 瀏覽:776
python中3怎樣 瀏覽:106
米10安卓11怎麼升安卓12 瀏覽:349
安卓屏幕模式有什麼用 瀏覽:203
iphone換魅族安卓如何轉移數據 瀏覽:777
linux安裝命令rpm 瀏覽:328
太原方特app哪裡下載 瀏覽:709
小黑加密照片 瀏覽:403
安卓apaid怎麼發朋友圈 瀏覽:857
怎麼幫安卓手機換電池 瀏覽:388
python做伺服器監控 瀏覽:905
如何將pdf文件轉成jpg 瀏覽:130
破解so文件源碼 瀏覽:927
怎麼用命令符修復病毒 瀏覽:237
假裝程序員怎麼做 瀏覽:945
輕量應用伺服器怎麼改模板 瀏覽:828