配置 ART

本頁討論如何配置 ART 及其編譯選項。此處討論的主題包括系統映像預編譯的配置、dex2oat 編譯選項以及如何權衡系統分區空間、數據分區空間和性能。

ART和的DalvikDalvik的可執行文件格式,並在source.android.com與藝術作品的剩餘頁面。請參閱在Android運行時(ART)驗證應用程序的行為,以確保您的應用正常工作。

藝術如何運作

ART 使用提前 (AOT) 編譯,從 Android 7.0(Nougat 或 N)開始,它使用 AOT、即時 (JIT) 編譯和配置文件引導編譯的混合組合。所有這些編譯模式的組合是可配置的,將在本節中討論。例如,Pixel 設備配置有以下編譯流程:

  1. 應用程序最初安裝時沒有進行任何 AOT 編譯。應用程序運行的前幾次,它會被解釋,頻繁執行的方法將被 JIT 編譯。
  2. 當設備空閒和充電時,編譯守護程序會運行以 AOT 編譯基於首次運行期間生成的配置文件的常用代碼。
  3. 應用程序的下一次重新啟動將使用配置文件引導的代碼,並避免在運行時對已編譯的方法進行 JIT 編譯。在新運行期間獲得 JIT 編譯的方法將被添加到配置文件中,然後編譯守護程序會選取這些方法。

ART包括編譯器(所述dex2oat工具)和運行時( libart.so )被加載用於啟動合子。該dex2oat工具將APK文件,並生成一個或多個編譯神器文件運行時負載。文件的數量、擴展名和名稱可能會因版本而異,但從 Android O 版本開始,生成的文件為:

  • .vdex :包含APK的未壓縮DEX代碼,具有加快驗證一些附加的元數據。
  • .odex :包含在APK方法AOT編譯代碼。
  • .art (optional)包含一些字符串和類在APK列出的,用於速度應用程序啟動的ART內部表示。

編譯選項

ART 的編譯選項分為兩類:

  1. 系統 ROM 配置:構建系統映像時哪些代碼會被 AOT 編譯。
  2. 運行時配置:ART 如何在設備上編譯和運行應用程序。

其中核心技術選項來配置這兩個類是編譯器的過濾器。編譯器過濾驅動技術如何DEX編譯代碼,並傳遞給一個選項dex2oat工具。從 Android O 開始,有四種官方支持的過濾器:

  • 驗證:只運行DEX代碼驗證。
  • 加快:DEX運行代碼驗證和優化一些DEX的指令,以獲得更好的性能的解釋。
  • 速度:DEX運行代碼驗證和AOT編譯的所有方法。
  • 速度曲線:DEX運行代碼驗證並在配置文件中列出的AOT編譯的方法。

系統ROM配置

有許多 ART 構建選項可用於配置系統 ROM。如何配置這些選項取決於為可用存儲空間/system和預裝的應用程序數量。編譯成系統ROM的JAR/APK可以分為四類:

  • 引導類路徑代碼:在默認情況下速度的編譯器編譯過濾器。
  • 系統服務器代碼:在默認情況下速度的編譯器編譯過濾器。
  • 特定產品的核心應用:在默認情況下速度的編譯器編譯過濾器。
  • 所有其他應用程序:在默認情況下的加快編譯器編譯過濾器。

生成文件選項

  • WITH_DEXPREOPT
  • 無論dex2oat調用安裝的系統映像DEX代碼。默認啟用。

  • DONT_DEXPREOPT_PREBUILTS (由於Android L)
  • 啟用DONT_DEXPREOPT_PREBUILTS防止了預優化的prebuilts。這些是具有應用include $(BUILD_PREBUILT)在其指定的Android.mk ,如Gmail。跳過預置的應用程序,有可能通過谷歌播放將被更新的預優化節省/system空間,但確實增加了,首先啟動時間。

  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER (由於Android 9)
  • PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER指定預先優化的應用程序的默認編譯器過濾。這些是具有應用include $(BUILD_PREBUILT)在其指定的Android.mk ,如Gmail。如果未指定,則默認值是加速。

  • WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY (新Android中ØMR1)
  • 啟用WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY預優化只是引導類路徑和系統服務器罐子。

  • LOCAL_DEX_PREOPT
  • 預優化還可以啟用或通過指定的個人應用的基礎上禁用LOCAL_DEX_PREOPT模塊定義選項。這對於禁用可能會立即接收 Google Play 更新的應用程序的預優化很有用,因為更新會使系統映像中的預優化代碼過時。這對於節省主要版本升級 OTA 的空間也很有用,因為用戶可能已經在數據分區中擁有更新版本的應用程序。

    LOCAL_DEX_PREOPT支持值“真”或“假”分別啟用或禁用預優化。此外,'nostripping'可如果預優化不應剝離指定classes.dex從APK或JAR文件的文件。通常這個文件會被剝離,因為在預優化後不再需要它,但最後一個選項是必要的,以允許第三方 APK 簽名保持有效。

  • PRODUCT_DEX_PREOPT_BOOT_FLAGS
  • 通過選項dex2oat引導映像如何編譯控制。它可用於指定自定義圖像類列表、編譯類列表和編譯器過濾器。

  • PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
  • 通過選項dex2oat如何除了引導映像一切都被編譯成控制。

  • PRODUCT_DEX_PREOPT_MODULE_CONFIGS
  • 提供傳遞能力dex2oat選項特定模塊和產品配置。它是在一個產品的設置device.mk文件由$(call add-product-dex-preopt-module-config,<modules>,<option>)其中<modules>是JAR和APK LOCAL_MODULE和LOCAL_PACKAGE名稱的列表文件,分別。

  • PRODUCT_DEXPREOPT_SPEED_APPS (New in Android O)
  • 那已被確定為核心,以產品,哪些是可取的速度編譯器過濾器來編譯應用程序列表。例如,像 SystemUI 這樣的持久性應用程序只有在下次重啟時才有機會使用配置文件引導編譯,因此產品最好讓這些應用程序始終使用 AOT 編譯。

  • PRODUCT_SYSTEM_SERVER_APPS (New in Android O)
  • 系統服務器加載的應用程序列表。這些應用程序會默認使用速度編譯器過濾器進行編譯。

  • PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD(Post Android O)
  • 是否在設備上包含調試版本的 ART。默認情況下,這對 userdebug 和 eng 構建啟用。該行為可以通過顯式設置選項為truefalse覆蓋。

    默認情況下,設備將使用非調試版本(libart.so)。要切換,設置系統屬性persist.sys.dalvik.vm.lib.2libartd.so。

  • WITH_DEXPREOPT_PIC (Removed in Android O)
  • 在的Android 5.1.0利用Android 6.0.1, WITH_DEXPREOPT_PIC可以指定,以使與位置無關的代碼(PIC)。有了這個,來自映像的編譯代碼不必從 /system 重定位到 /data/dalvik-cache,從而節省了數據分區中的空間。但是,運行時會受到輕微影響,因為它禁用了利用位置相關代碼的優化。通常,想要在 /data 中節省空間的設備應該啟用 PIC 編譯。

    在 Android 7.0 中,默認啟用 PIC 編譯。

  • WITH_DEXPREOPT_BOOT_IMG_ONLY (Android中öMR1移除)
  • 此選項已替換為 WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY,它也預先選擇了系統服務器 jar。

引導類路徑配置

  • 預加載類列表
  • 預加載類列表是 zygote 在啟動時初始化的類列表。這使每個應用程序不必單獨運行這些類初始值設定項,從而使它們能夠更快地啟動並在內存中共享頁面。所述預裝類列表文件位於frameworks/base/config/preloaded-classes在默認情況下,它其中包含的調整為典型的電話使用清單。對於可穿戴設備等其他設備,這可能有所不同,因此必須進行相應調整。調整時要小心;添加太多類會在加載未使用的類時浪費內存。添加太少的類會迫使每個應用程序都必須擁有自己的副本,這又會浪費內存。

    示例用法(在產品的 device.mk 中):

    PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
    

    注意:此行必須放在繼承任何產品配置的makefile是得到默認的一個前: build/target/product/base.mk

  • 圖像類列表
  • 圖像類列表是 dex2oat 提前初始化並存儲在 boot.art 文件中的類列表。這允許 zygote 在啟動時從 boot.art 文件加載這些結果,而不是在預加載期間運行這些類本身的初始化程序。這樣做的一個關鍵特性是從圖像加載並在進程之間共享的頁面可以是乾淨的,允許它們在低內存情況下輕鬆換出。在 L 中,默認情況下圖像類列表使用與預加載類列表相同的列表。從 AOSP 中的 post-L 開始,可以使用以下命令指定自定義圖像類列表:

    PRODUCT_DEX_PREOPT_BOOT_FLAGS
    

    例如使用(在產品的device.mk ):

    PRODUCT_DEX_PREOPT_BOOT_FLAGS += --image-classes=<filename>
    
  • 編譯類列表
  • 在 L 後 AOSP 中,可以在預優化期間使用已編譯的類列表指定要編譯的引導類路徑中的類的子集。對於空間非常緊張且無法容納整個預優化啟動映像的設備,這可能是一個有用的選項。但是,未在此列表中指定的註釋類不會被編譯 - 即使在設備上也不會 - 並且必須被解釋,這可能會影響運行時性能。默認情況下,dex2oat 將在 $OUT/system/etc/compiled-classes 中查找已編譯的類列表,因此可以通過 device.mk 將自定義類複製到該位置。 :特定的文件的位置,也可以使用指定

    PRODUCT_DEX_PREOPT_BOOT_FLAGS
    

    示例性的使用(以產品的device.mk ):

    PRODUCT_COPY_FILES += <filename>:system/etc/compiled-classes
    

    注意:此行必須放在繼承任何產品配置的makefile是得到默認的一個前: build/target/product/base.mk

運行時配置

即時選項

以下選項僅在 ART JIT 編譯器可用的情況下影響 Android 版本。

  • dalvik.vm.usejit:是否啟用 JIT。
  • dalvik.vm.jitinitialsize(默認64K):代碼緩存的初始容量。代碼緩存將定期 GC 並在需要時增加。
  • dalvik.vm.jitmaxsize(默認64M):代碼緩存的最大容量。
  • dalvik.vm.jitthreshold:(默認 10000) - 這是一個方法的“熱度”計數器需要通過的閾值,以便該方法被 JIT 編譯。 “熱度”計數器是運行時內部的指標。它包括調用次數、後向分支和其他因素。
  • dalvik.vm.usejitprofiles:是否啟用 JIT 配置文件;即使 dalvik.vm.usejit 為假,這也可以使用。需要注意的是,如果這是假的,編譯器過濾速度配置文件不AOT編譯的任何方法,相當於加快
  • dalvik.vm.jitprithreadweight(默認為 dalvik.vm.jitthreshold / 20) - 應用程序 UI 線程的 JIT“樣本”(參見 jitthreshold)的權重。用於加速直接影響用戶與應用程序交互時體驗的方法的編譯。
  • dalvik.vm.jittransitionweight:(默認為 dalvik.vm.jitthreshold / 10)在編譯代碼和解釋器之間轉換的方法調用的權重。這有助於確保編譯所涉及的方法以最小化轉換(這是昂貴的)。

包管理器選項

從 Android 7.0 開始,有一種通用方法可以指定在各個階段發生的編譯/驗證級別。編譯級別可以通過系統屬性進行配置,默認值為:

  • pm.dexopt.install=speed-profile
  • 這是通過 Google Play 安裝應用程序時使用的編譯過濾器。我們建議將安裝過濾器設置為 speed-profile 以啟用來自 dex 元數據文件的配置文件。請注意,如果未提供配置文件或如果它為空,則速度配置文件等效於加速。

  • pm.dexopt.bg-dexopt=speed-profile
  • 這是設備空閒、充電和充滿電時使用的編譯過濾器。試試速度曲線編譯器過濾器利用檔案導引編譯,節省存儲空間。

  • pm.dexopt.boot=verify
  • 無線更新後使用的編譯過濾器。我們強烈建議驗證編譯器過濾器此選項可避免很長的啟動時間。

  • pm.dexopt.first-boot=quicken
  • 設備首次啟動時的編譯過濾器。這裡使用的過濾器只會影響出廠後的開機時間。我們建議加快進行,以避免用戶獲得使用手機的第一次之前長的時間過濾器。請注意,如果在所有的應用/system已經與加快編譯器過濾器編譯或轉速速度曲線編譯器過濾器在編譯時, pm.dexopt.first-boot沒有任何影響。

Dex2oat 選項

請注意,這些選項會影響dex2oat設備上的編譯過程中,以及預優化過程中,而大多數的選項上面討論只影響預優化。

為了控制dex2oat ,而它的編譯引導映像:

  • dalvik.vm.image-dex2oat-Xms:初始堆大小
  • dalvik.vm.image-dex2oat-Xmx:最大堆大小
  • dalvik.vm.image-dex2oat-filter:編譯器過濾選項
  • dalvik.vm.image-dex2oat-threads:使用的線程數

為了控制dex2oat ,而它的編譯除了引導映像的一切:

  • dalvik.vm.dex2oat-Xms:初始堆大小
  • dalvik.vm.dex2oat-Xmx:最大堆大小
  • dalvik.vm.dex2oat-filter:編譯器過濾選項

在 Android 6.0 之前的版本中,提供了一個額外的選項來編譯除啟動映像之外的所有內容:

  • dalvik.vm.dex2oat-threads:使用的線程數

從 Android 6.1 開始,這成為編譯除啟動映像之外的所有內容的兩個附加選項:

  • dalvik.vm.boot-dex2oat-threads:啟動時使用的線程數
  • dalvik.vm.dex2oat-threads:啟動後使用的線程數

從 Android 7.1 開始,提供了兩個選項來控制在編譯除啟動映像之外的所有內容時如何使用內存:

  • dalvik.vm.dex2oat-very-large:禁用 AOT 編譯的最小總 dex 文件大小(以字節為單位)
  • dalvik.vm.dex2oat-swap:使用 dex2oat 交換文件(用於低內存設備)

控制初始和最大堆大小的選項dex2oat不應該減少,因為它們可能會限制可以編譯哪些應用程序。

從 Android 11 開始,提供了三個 CPU 關聯選項以允許將編譯器線程限制為特定的 CPU 組:

  • dalvik.vm.boot-dex2oat-cpu-set:啟動期間運行 dex2oat 線程的 CPU
  • dalvik.vm.image-dex2oat-cpu-set:編譯啟動鏡像時運行 dex2oat 的 CPU
  • dalvik.vm.dex2oat-cpu-set:啟動後運行 dex2oat 線程的 CPU

CPU 應指定為以逗號分隔的 CPU id 列表。例如,要在 CPU 0-3 上的 dex2oat 上運行,請設置:

dalvik.vm.dex2oat-cpu-set=0,1,2,3

在設置 CPU 親和性屬性時,我們建議匹配 dex2oat 線程數的對應屬性,以匹配選擇的 CPU 數,以避免不必要的內存和 I/O 爭用:

dalvik.vm.dex2oat-cpu-set=0,1,2,3
dalvik.vm.dex2oat-threads=4

A/B 具體配置

ROM配置

在的Android 7.0開始,設備可以使用兩個系統分區,以使A / B系統更新。為了節省系統分區大小,可以將預先選擇的文件安裝在未使用的第二個系統分區中。然後在第一次啟動時將它們複製到數據分區。

實施例使用(在device-common.mk ):

PRODUCT_PACKAGES += \
     cppreopts.sh
PRODUCT_PROPERTY_OVERRIDES += \
     ro.cp_system_other_odex=1

而在設備的BoardConfig.mk

BOARD_USES_SYSTEM_OTHER_ODEX := true

請注意,引導類路徑代碼、系統服務器代碼和特定於產品的核心應用程序始終編譯到系統分區。默認情況下,所有其他應用程序都被編譯到未使用的第二個系統分區。這可以通過控制SYSTEM_OTHER_ODEX_FILTER ,其具有由缺省值:

SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%

後台dexopt OTA

使用支持 A/B 的設備,可以在後台編譯應用程序以更新到新的系統映像。見在後台應用程序編譯以任選地包括在系統中的圖像編輯腳本和二進制文件。用於此編譯的編譯過濾器由以下各項控制:

pm.dexopt.ab-ota=speed-profile

我們建議使用速度型,可利用profile指導編制和節省存儲空間。