淺談Android系統(tǒng)的基本體系結(jié)構(gòu)與內(nèi)存管理優(yōu)化
Android運行環(huán)境一覽
Android基于linux內(nèi)核,面向移動終端的操作系統(tǒng)。主要包括以下幾個方面:
Application Framework:
這一層為應用開發(fā)者提供了豐富的應用編程接口,如 Activity Manager,Content Provider,Notification Manager,以及各種窗口 Widget 資源等。所有的APP都是運行在這一層之上。
Dalvik 虛擬機:
Dalvik VM采用寄存器架構(gòu),而不是JVM的棧架構(gòu),更適于移動設備。java源代碼經(jīng)過編譯成為.class字節(jié)碼文件,然后由谷歌提供的 dx工具將其轉(zhuǎn)化為Dalvik可識別的.dex文件。
Linux kernel:
每個APP應用程序由一個獨立的Dalvik VM來解釋執(zhí)行,而一個Dalvik VM實例對應一個linux內(nèi)核進程。
所以說,每個APP之間完全隔離,資源獨立。使得每個APP更加安全,但也不利于進程間通信

Android官方介紹

**Android 系統(tǒng)架構(gòu)
Application framework
大部分開發(fā)者十分關心這一層。你必須要了解開發(fā)者會接觸到的所有API接口,大部分接口都與硬件抽象層(HAL層)接口一一對應,而且它們會告訴你如何實現(xiàn)你自己的驅(qū)動。
Binder IPC
Binder進程間通信機制幫助Application framework層能夠跨進程并且調(diào)用系統(tǒng)級服務。從根本上講,它幫助高級別的framework的API接口與Android系統(tǒng)服務進行交互。
系統(tǒng)服務
大部分Application framework api具備的功能都要依靠與某種系統(tǒng)服務進行通信從而操作底層硬件。系統(tǒng)服務根據(jù)不同的功能分成了若干模塊組件,例如Window Manager, Search Service, or Notification Manager。系統(tǒng)服務主要包含兩大塊:系統(tǒng)和媒體。前者對應的服務包含如Window Manager 或 Notification Manager,后者對應的服務都與播放或記錄媒體有關。
硬件抽象層Hardware abstraction layer (HAL)
硬件抽象層可以作為一個標準接口讓Android系統(tǒng)調(diào)用設備驅(qū)動層而不用管這些驅(qū)動和硬件時如何實現(xiàn)的。
![硬件驅(qū)動層相關組件]
Linux Kernel
大多數(shù)情況下,你自己開發(fā)設備驅(qū)動和開發(fā)linux設備驅(qū)動時一樣的。Android挑選了一個特定的linux內(nèi)核版本,這個版本包含了如wakelocks(一個內(nèi)存管理系統(tǒng)),Binder IPC驅(qū)動和其他一些特征,這些特征對于像Android一樣的移動嵌入式平臺都非常重要。你也可以根據(jù)自己的需求選擇合適的kernel版本,只要它能支持一些必要的屬性如Binder IPC驅(qū)動等。但是,我們?nèi)匀煌扑]你使用最新版本的Android內(nèi)核。具體可參考內(nèi)核編譯
相關知識點:
應用程序進程間隔離機制:
Android系統(tǒng)包括四層架構(gòu):從底層往上依次是Linux kernel層、C/C++函數(shù)庫與Android運行時環(huán)境(Dalvik VM等)層、Android Framwork框架層、應用程序?qū)?。其中,Android運行時環(huán)境層類似Java里的JRE層,主要用來運行java程序,不過此處的虛擬機是Dalvik虛擬機。每一個Android應用程序都運行在單獨的Davlik進程里,Dalvik虛擬機針對同時高效運行多個虛擬機而優(yōu)化,在這一層實現(xiàn)了應用程序的進程間隔離。
Dalvik虛擬機與JVM區(qū)別:
JVM直接從.class或Jar包中加載字節(jié)碼解釋運行,Dalvik通過DX工具將.class文件編譯為.dex文件(Dalvik Executable)來運行。
JVM采用棧結(jié)構(gòu),而Dalvik采用寄存器結(jié)構(gòu),更適于移動設備。
為何Android要采用Dalvik虛擬機而不是JVM呢?
大多數(shù)虛擬機(包括JVM)都是基于棧的,而Dalvik虛擬機則是基于寄存器的,性能更好,不過也導致硬件通用性略差;
運行專有.dex文件。DX工具對.class文件編譯時,去除里面的冗余信息,并把所有.class文件整合到一個文件中,提高了性能。同時DX工具還會對.dex文件進行性能優(yōu)化。
內(nèi)存管理及優(yōu)化
一、Android內(nèi)存基礎
物理內(nèi)存與進程內(nèi)存
物理內(nèi)存即移動設備上的RAM,當啟動一個Android程序時,會啟動一個Dalvik VM進程,系統(tǒng)會給它分配固定的內(nèi)存空間(16M,32M不定),這塊內(nèi)存空間會映射到RAM上某個區(qū)域。然后這個Android程序就會運行在這塊空間上。Java里會將這塊空間分成Stack棧內(nèi)存和Heap堆內(nèi)存。stack里存放對象的引用,heap里存放實際對象數(shù)據(jù)。
在程序運行中會創(chuàng)建對象,如果未合理管理內(nèi)存,比如不及時回收無效空間就會造成內(nèi)存泄露,嚴重的話可能導致使用內(nèi)存超過系統(tǒng)分配內(nèi)存,即內(nèi)存溢出OOM,導致程序卡頓甚至直接退出。
內(nèi)存泄露(Memory Leak)
Java內(nèi)存泄漏指的是進程中某些對象(垃圾對象)已經(jīng)沒有使用價值了,但是它們卻可以直接或間接地引用到gc roots導致無法被GC回收。Dalvik VM具備的GC機制(垃圾回收機制)會在內(nèi)存占用過多時自動回收,嚴重時會造成內(nèi)存溢出OOM。
內(nèi)存溢出OOM
當應用程序申請的java heap空間超過Dalvik VM HeapGrowthLimit時,溢出。
注意:OOM并不代表內(nèi)存不足,只要申請的heap超過Dalvik VM HeapGrowthLimit時,即使內(nèi)存充足也會溢出。效果是能讓較多進程常駐內(nèi)存。
如果RAM不足時系統(tǒng)會做什么?
Android的Memory Killer會殺死優(yōu)先級較低的進程,讓高優(yōu)先級進程獲取更多內(nèi)存。
Android系統(tǒng)默認內(nèi)存回收機制
進程優(yōu)先級:Foreground進程、Visible進程、Service進程、Background進程、Empty進程;
如果用戶按Home鍵返回桌面,那么該app成為Background進程;如果按Back返回,則成為Empty進程
ActivityManagerService直接管理所有進程的內(nèi)存資源分配。所有進程要申請或釋放內(nèi)存都需要通過ActivityManagerService對象。
垃圾回收不定期執(zhí)行。當內(nèi)存不夠時就會遍歷heap空間,把垃圾對象刪除。
堆內(nèi)存越大,則GC的時間更長

二、優(yōu)化
Bitmap優(yōu)化
Bitmap非常消耗內(nèi)存,而且在Android中,讀取bitmap時, 一般分配給虛擬機的圖片堆棧只有8M,所以經(jīng)常造成OOM問題。所以有必要針對Bitmap的使用作出優(yōu)化:
- 圖片顯示:加載合適尺寸的圖片,比如顯示縮略圖的地方不要加載大圖。
- 圖片回收:使用完bitmap,及時使用Bitmap.recycle()回收。
- 問題:Android不是自身具備垃圾回收機制嗎?此處為何要手動回收。
- Bitmap對象不是new生成的,而是通過BitmapFactory生產(chǎn)的。而且通過源碼可發(fā)現(xiàn)是通過調(diào)用JNI生成Bitmap對象(nativeDecodeStream()等方法)。所以,加載bitmap到內(nèi)存里包括兩部分,Dalvik內(nèi)存和Linux kernel內(nèi)存。前者會被虛擬機自動回收。而后者必須通過recycle()方法,內(nèi)部調(diào)用nativeRecycle()讓linux kernel回收。
- 捕獲OOM異常:程序中設定如果發(fā)生OOM的應急處理方式。
- 圖片緩存:內(nèi)存緩存、硬盤緩存等
- 圖片壓縮:直接使用ImageView顯示Bitmap時會占很多資源,尤其當圖片較大時容易發(fā)生OOM??梢允褂肂itMapFactory.Options對圖片進行壓縮。
- 圖片像素:android默認顏色模式為ARGB_8888,顯示質(zhì)量最高,占用內(nèi)存最大。若要求不高時可采用RGB_565等模式。圖片大?。簣D片長度*寬度*單位像素所占據(jù)字節(jié)數(shù)
- ARGB_4444:每個像素占用2byte內(nèi)存
- ARGB_8888:每個像素占用4byte內(nèi)存 (默認)
- RGB_565:每個像素占用2byte內(nèi)存
對象引用類型
強引用 strong:Object object=new Object()。當內(nèi)存不足時,Java虛擬機寧愿拋出OOM內(nèi)存溢出異常,也不會輕易回收強引用對象來解決內(nèi)存不足問題;
軟引用 soft:只有當內(nèi)存達到某個閾值時才會去回收,常用于緩存;
弱引用 weak :只要被GC線程掃描到了就進行回收;
虛引用
如果想要避免OOM發(fā)生,則使用軟引用對象,即當內(nèi)存快不足時進行回收;如果想盡快回收某些占用內(nèi)存較大的對象,例如bitmap,可以使用弱引用,能被快速回收。不過如果要對bitmap作緩存就不要使用弱引用,因為很快就會被GC回收,導致緩存失敗。
池 pool
對象池:如果某個對象在創(chuàng)建時,需要較大的資源開銷,那么可以將其放入對象池,即將對象保存起來,下次需要時直接取出使用,而不用再次創(chuàng)建對象。當然,維護對象池也需要一定開銷,故要衡量。
線程池:與對象池差不多,將線程對象放在池中供反復使用,減少反復創(chuàng)建線程的開銷。
相關文章
Android開發(fā)實現(xiàn)按鈕點擊切換背景并修改文字顏色的方法
這篇文章主要介紹了Android開發(fā)實現(xiàn)按鈕點擊切換背景并修改文字顏色的方法,涉及Android界面布局與相關屬性設置技巧,需要的朋友可以參考下2018-01-01
Android 狀態(tài)欄虛擬導航鍵透明效果的實現(xiàn)方法
這篇文章主要介紹了Android 狀態(tài)欄虛擬導航鍵透明效果的實現(xiàn)方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03
Kotlin中實現(xiàn)多線程數(shù)據(jù)刷新的完整方案
這篇文章主要介紹了Kotlin中實現(xiàn)多線程數(shù)據(jù)刷新的完整方案,本文通過實例代碼給大家介紹的非常詳細,感興趣的朋友一起看看吧2025-04-04
Kotlin中內(nèi)置函數(shù)的用法和區(qū)別總結(jié)
眾所周知相比Java, Kotlin提供了不少高級語法特性。對于一個Kotlin的初學者來說經(jīng)常會寫出一些不夠優(yōu)雅的代碼。下面這篇文章主要給大家介紹了關于Kotlin中內(nèi)置函數(shù)的用法和區(qū)別的相關資料,需要的朋友可以參考下2018-06-06

