Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 性能優化 內存優化之How Android Managers Memory(一)

Android 性能優化 內存優化之How Android Managers Memory(一)

編輯:關於Android編程

前言

在學習Android內存性能優化時,發現需要對Android系統的內存概況得有個概況了解,便有了此篇文章。
這篇文章僅僅介紹相關於內存的,即輔助理解 官方文檔 How Android Manages Memory。將會從Android啟動開始,一直到因為內存不足開始殺死進程回收內存結束,方便後來的學習。內容太多,將分兩篇寫。本篇主要介紹基礎概念,下篇介紹Android如何進行內存管理。

1. Android系統介紹

Android 是一款基於 Linux 內核,面向移動終端的操作系統。 Android並不是傳統的Linux風格的一個規范或分發版本,也不是一些列可重用的組件集成,Android是一個用於連接設備的軟件塊。

Android系統的四層架構圖:
Android四層架構

系統啟動時就是從底層往上一層一層啟動的。

2. Android系統啟動

startupStep

電源鍵 –> Boot ROM,加載引導程序 –> Linux Kernel 啟動內核 –> init進程(第一個進程)。

第五步、第六步:
1. init進程開始運行:創建目錄,掛載設備,初始化屬性,加載配置文件(init.rc),開啟守護進程,在init.rc配置文件中 就啟動了Zygote進程,由init進程通過fork而來。
2. 調用app_main.cpp文件的AppRuntime.start()方法,在父類AndroidRuntime中:啟動Dalvik虛擬機,注冊JNI,啟動ZygoteInit的main()方法
3. ZygoteInit中預加載類preloadClassed()、預加載資源preloadResources()等,然後啟動 startSystemServer。
4. SystemServer 首先通過init1()方法加載Libraries中的核心類庫,然後又通過init2()方法啟動 ServerThread線程,啟動 Framework下的各種服務。
5. 然後ActivityManagerService啟動Launcher應用,Launcher是一個app,會獨占一個進程,Launcher在啟動的時候便會通過PackageManagerService把系統中已經安裝好的應用程序以快捷圖標的形式展示在桌面上,這樣用戶就可以使用這些應用程序了。

init 進程

3. Dalvik簡介和ART簡介

Dalvik虛擬機垃圾收集機制簡要介紹和學習計劃 理解Android虛擬機體系結構 wiki-Dalvik虛擬機

Dalvik虛擬機與Java虛擬機的區別,其中Dalvik虛擬機不能執行.class文件:

它們分別具有不同的類文件格式以及指令集。Dalvik虛擬機使用的是dex(Dalvik Executable)格式的類文件,而Java虛擬機使用的是class格式的類文件。由於一個dex文件可以包含若干個類,因此它就可以將各個類中重復的字符串和其它常數只保存一次,從而節省了空間,這樣就適合在內存和處理器速度有限的手機系統中使用。 Dalvik虛擬機使用的指令是基於寄存器的,而Java虛擬機使用的指令集是基於堆棧的。

Dalvik虛擬機優化措施:

將多個類文件收集到同一個dex文件中,以便節省空間; 使用只讀的內存映射方式加載dex文件,以便可以多進程共享dex文件,節省程序加載時間; 提前調整好字節序(byte order)和字對齊(word alignment)方式,使得它們更適合於本地機器,以便提高指令執行速度; 盡量提前進行字節碼驗證(bytecode verification),提高程序的加載速度; 需要重寫字節碼的優化要提前進行。

使用odex文件加快響應速度
Apk在安裝(installer)時,就會進行驗證和優化,目的是為了校驗代碼合法性及優化代碼執行速度,驗證和優化後,會產生ODEX文件,運行Apk的時候,直接加載ODEX,避免重復驗證和優化,加快了Apk的響應時間。
odex是OptimizedDEX的縮寫,表示經過優化的dex文件。存放在/data/dalvik-cache目錄下。由於Android程序的apk文件為zip壓縮包格式,Dalvik虛擬機每次加載它們時需要從apk中讀取classes.dex文件,這樣會耗費很多cpu時間,而采用odex方式優化的dex文件,已經包含了加載dex必須的依賴庫文件列表,Dalvik虛擬機只需檢測並加載所需的依賴庫即可執行相應的dex文件,這大大縮短了讀取dex文件所需的時間。

Dalvik虛擬機內存:
Dalvik虛擬機的內存大體上可以分為Java Object Heap、Bitmap Memory和Native Heap三種。其中Bitmap Memory在HoneyComb以及更高的版本中直接是在Java Object Heap中分配了,這樣就可以直接接受GC的管理。
這個Java Object Heap的最大值也就是我們平時所說的Android應用程序進程能夠使用的最大內存。
通過命令行:adb shell getprop | grep heap可查看系統所分配的最大內存。

Dalvik和ART(Android runtime)
在Dalvik下,應用每次運行的時候,字節碼都需要通過即時編譯器(just in time ,JIT)轉換為機器碼,這會拖慢應用的運行效率,而在ART 環境中,應用在第一次安裝的時候,字節碼就會預先編譯成機器碼,使其成為真正的本地應用。這個過程叫做預編譯(AOT,Ahead-Of-Time)。
ART能夠把應用程序的字節碼轉換為機器碼,是Android所使用的一種新的虛擬機。它與Dalvik的主要不同在於:Dalvik采用的是JIT技術,而ART采用Ahead-of-time(AOT)技術。ART同時也改善了性能、垃圾回收(Garbage Collection)、應用程序除錯以及性能分析。

JIT和AOT
JIT是在程序運行的過程中進行編譯的,而AOT是在程序運行前進行編譯的。

4. 應用程序啟動分析

Launcher 接收到點擊事件,通過PackageManager獲取到應用的信息,通過Binder向 SystemServer(ActivityManagerService 簡稱AMS 運行在裡面) 發起啟動應用的請求。 SystemServer(AMS) 請求 Launcher Pause (Launcher 需要保存狀態進入後台) Launcher Pause後, 向 SystemServer(AMS) 發送 Pause 完畢 SystemServer(AMS) 向 Zygote 請求啟動一個新進程 Zygote fork出一個新進程,用來啟動一個ActivityThread實例,即將要啟動的Activity就是在這個ActivityThread實例中運行, 在新進程中執行 ActivityThread 類的 main 方法 ActivityThread通過Binder將一個ApplicationThread類型的Binder對象傳遞給ActivityManagerService。 ActivityManagerService調用ApplicationThread.scheduleLaunchActivity接口,通知相應的進程執行啟動Activity的操作; ApplicationThread把這個啟動Activity的操作轉發給ActivityThread,ActivityThread通過ClassLoader導入相應的Activity類,然後把它啟動起來。

其中ActivityManagerServices,簡稱AMS,服務端對象,負責系統中所有Activity的生命周期。ActivityThread是App的真正入口。當開啟App之後,會調用main()開始運行,開啟消息循環隊列,這就是傳說中的UI線程或者叫主線程。

啟動App時通過fork Zygote進程來節約內存:

在Java中,我們知道不同的虛擬機實例會為不同的應用分配不同的內存。如果Android系統也這樣,為每一個應用啟動不同的Dalvik虛擬機實例,就會消耗大量的內存以及時間。因此,為了克服這個問題,Android系統創造了Zygote。Zygote讓Dalvik虛擬機共享代碼、低內存占用以及最小的啟動時間成為可能。Zygote是一個虛擬器進程,正如我們在前一個步驟所說的在系統引導的時候啟動。Zygote預加載以及初始化核心庫類。通常,這些核心類一般是只讀的,也是Android SDK或者核心框架的一部分。

Zygote進程在啟動的時候,會創建一個虛擬機實例,並且在這個虛擬機實例將所有的Java核心庫都加載起來。每當Zygote進程需要創建一個Android應用程序進程的時候,它就通過復制自身來實現,也就是通過fork系統調用來實現。這些被fork出來的Android應用程序進程,一方面是復制了Zygote進程中的虛擬機實例,另一方面是與Zygote進程共享了同一套Java核心庫。這樣不僅Android應用程序進程的創建過程很快,而且由於所有的Android應用程序進程都共享同一套Java核心庫而節省了內存空間。

一個應用程序進程被Zygote進程孵化出來的時候,不僅會獲得Zygote進程中的Dalvik虛擬機實例拷貝,還會與Zygote一起共享Java運行時庫,這完全得益於Linux內核的進程創建機制(fork)。這種Zygote孵化機制的優點是不僅可以快速地啟動一個應用程序進程,還可以節省整體的內存消耗,缺點是會影響開機速度,但是畢竟Zygote是在開機過程中啟動的,總體來說,是利大於弊的,畢竟整個系統只有一個Zygote進程,而可能有無數個應用程序進程,而且我們不會經常去關閉手機,大多數情況下只是讓它進入休眠狀態。

官方文檔:Sharing Memory
Each app process is forked from an existing process called Zygote. To start a new app process, the system forks the Zygote process then loads and runs the app’s code in the new process. This approach allows most of the RAM pages allocated for framework code and resources to be shared across all app processes.

結語:

本篇文章主要介紹Android如何啟動、應用程序如何啟動,以及Dalvik虛擬機和ART虛擬機,有這些基礎概念知識後,再梳理下篇Android如何管理Memory就會方便很多。
因為本篇介紹的東西都大而難,難免會有錯誤,大家多看看參考鏈接。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved