在 Android 執行階段 (ART) 驗證應用程式行為

Android 執行階段 (ART) 是執行 Android 裝置的預設執行階段 5.0 (API 級別 21) 以上版本。這個執行階段提供多種功能 。 如要進一步瞭解 ART 的新功能,請參閱「隆重推出 ART

不過,某些 Dalvik 可用的技術無法在 ART 上運作。這個 這份文件會說明在 才能與 ART 相容。在使用指令列執行時, ART,

解決垃圾收集 (GC) 問題

在 Dalvik 底下,應用程式經常覺得明確呼叫 System.gc() 可提示垃圾收集 (GC)。這應該是 遠比使用 ART 需要得多,尤其在叫用垃圾收集時更是如此 避免包含 GC_FOR_ALLOC 類型的廣告 或減少片段您可以確認目前正在使用的執行階段 呼叫 System.getProperty("java.vm.version")。如果 ART 使用中,屬性值 為 "2.0.0" 以上。

ART 使用並行複製 (CC) 收集器,後者會同時壓縮 Java 堆積。 因此,請避免同時使用 與壓縮 GC 不相容 (例如:將指標儲存至物件) 執行個體資料)。如果應用程式會使用 Java Native Interface (JNI)。詳情請參閱防範 JNI 問題

防止 JNI 問題

ART 的 JNI 比 Dalvik 更嚴格。這是一個特別好的方法 並使用 CheckJNI 模式找出常見問題。如果應用程式使用 C/C++ 程式碼,您應查看以下文章:

偵錯 搭配 CheckJNI 使用的 Android JNI

檢查 JNI 程式碼是否有垃圾收集問題

並行複製 (CC) 收集器可能會移動記憶體中的物件以進行壓縮。 如果使用 C/C++ 程式碼,請勿使用 執行與精簡 GC 不相容的作業。我們強化了 檢查 JNI 找出一些潛在問題 (如 JNI 中所述) ICS 中的本機參考資料變更)。

特別留意的領域是 「Get...ArrayElements()」和「Release...ArrayElements()」 函式。在含有非密集 GC 的執行階段中 Get...ArrayElements() 函式通常會傳回對 實際記憶體支援陣列物件如果您變更其中一個 傳回的陣列元素,則陣列物件本身會變更 (而 至 Release...ArrayElements() 通常會遭到忽略)。不過, 如果使用精簡的 GC,Get...ArrayElements() 函式可能會 傳回記憶的副本如果您在壓縮 GC 時誤用了該參考資料: 否則可能會導致記憶體損毀或其他問題。例如:

  • 如果您對傳回的陣列元素進行任何變更,就必須呼叫 並調整到適當的 Release...ArrayElements() 函式 以確保您所做的變更正確地複製回 陣列物件。
  • 釋放記憶體陣列元素時,必須使用 模式,視您執行的變更而定:
    • 如果您未變更陣列元素,請使用 JNI_ABORT 模式,會在未複製的情況下釋出記憶體 會變更回基礎陣列物件
    • 如果您變更了陣列,且不需要該參照任何 此外,請使用程式碼 0 (更新陣列物件並釋出 就會產生這類訊息
    • 如果您變更了要修訂的陣列,且希望 保留陣列副本,請使用 JNI_COMMIT (更新的內容會更新) 並保留副本)。
  • 呼叫 Release...ArrayElements() 時,會傳回相同的結果 原本由 Get...ArrayElements() 傳回的指標。適用對象 舉例來說,遞增原始指標 (如要完整瀏覽 然後再將遞增的指標傳送至 Release...ArrayElements()。傳送這個修改的指標可能導致 導致記憶體損毀。

處理錯誤

在 Dalvik 沒有的情況下,ART 的 JNI 會擲回錯誤。(一次 您也可以用 CheckJNI 進行測試,藉此掌握許多這類情況。)

例如,如果使用以下方法呼叫 RegisterNatives: 不存在 (原因可能是該方法已由如 ProGuard),ART 現在可以正確擲回 NoSuchMethodError

08-12 17:09:41.082 13823 13823 E AndroidRuntime: FATAL EXCEPTION: main
08-12 17:09:41.082 13823 13823 E AndroidRuntime: java.lang.NoSuchMethodError:
    no static or non-static method
    "Lcom/foo/Bar;.native_frob(Ljava/lang/String;)I"
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.nativeLoad(Native Method)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.doLoad(Runtime.java:421)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.Runtime.loadLibrary(Runtime.java:362)
08-12 17:09:41.082 13823 13823 E AndroidRuntime:
    at java.lang.System.loadLibrary(System.java:526)

如果 RegisterNatives 無效,ART 也會記錄錯誤 (顯示在 logcat 中) 不使用方法呼叫:

W/art     ( 1234): JNI RegisterNativeMethods: attempt to register 0 native
methods for <classname>

此外,JNI 函式為 GetFieldID()GetStaticFieldID() 現已正確擲回 NoSuchFieldError 而不是直接傳回空值同樣地,GetMethodID()GetStaticMethodID() 現在可以正確擲回 NoSuchMethodError。 這可能會導致 CheckJNI 失敗,原因是未處理的例外狀況或 原生程式碼的 Java 呼叫端擲回例外狀況。如此一來 尤其重要的是,使用 CheckJNI 模式測試與 ART 相容的應用程式。

ART 預期 JNI CallNonvirtual...Method() 方法的使用者 (例如 CallNonvirtualVoidMethod()) 會使用方法的宣告 而非子類別。

避免堆疊大小問題

Dalvik 針對原生程式碼和 Java 程式碼使用不同的堆疊,具有預設的 Java 堆疊大小為 32 KB,且預設的原生堆疊大小為 1 MB。ART 具有統一的 以獲得更準確的位置。通常情況下,ART Thread 堆疊 應該與 Dalvik 的大小大致相同不過,如果您已明確設定 設定堆疊大小後,您可能需要為執行中的應用程式重新檢查這些值 ART,

  • 在 Java 中,查看對指定明確堆疊的 Thread 建構函式呼叫 大小舉例來說,如果發生 StackOverflowError,就需要放大大小。
  • 在 C/C++ 中,查看 pthread_attr_setstack()pthread_attr_setstacksize():如果執行緒也會透過以下方式執行 Java 程式碼 JNI。以下是應用程式嘗試呼叫 JNI 時記錄的錯誤範例 AttachCurrentThread()
    F/art: art/runtime/thread.cc:435]
        Attempt to attach a thread with a too-small stack (16384 bytes)

物件模型變更

Dalvik 允許子類別錯誤地覆寫套件的私人方法。 在這種情況下,ART 會顯示警告:

Before Android 4.1, method void com.foo.Bar.quux()
would have incorrectly overridden the package-private method in
com.quux.Quux

如要覆寫其他套件中的類別方法,請宣告 publicprotected 方法。

Object 現在有不公開欄位。反映不同領域的應用程式 都應小心不要嘗試查看 Object 的欄位。舉例來說,如果您要疊代類別 做為序列化架構的一部分,

Class.getSuperclass() == java.lang.Object.class

而不是繼續作業,直到方法傳回 null 為止。

Proxy InvocationHandler.invoke() 現在會在沒有發生的情況下接收 null 而非空白陣列此行為已經記錄下來, 在 Dalvik 中未正確處理。Mockito 較舊版本的 所以在使用 ART 進行測試時,請使用更新的 Mockito 版本。

修正 AOT 編譯問題

ART 的預先 (AOT) Java 編譯應適用於所有標準 Java 再也不是件繁重乏味的工作編譯作業是由 ART 的 dex2oat 工具;如果發生 安裝時「dex2oat」,請向我們回報 (請參閱「回報問題」一節),以便我們盡快修復。 。請注意以下幾個問題:

  • 與 Dalvik 相比,ART 在安裝時執行位元碼驗證作業更為嚴格。 Android 建構工具產生的程式碼應該沒有問題。不過, 後期處理工具 (尤其是執行模糊處理工具) 的 Dalvik 容許,但遭到 ART 拒絕的無效檔案。我們 與工具供應商合作,找出並修正這類問題。在許多情況下 最新版本的工具並重新產生 DEX 檔案,即可修正問題 如要解決關聯問題,可用 Apriori 這類關聯規則學習技術和演算法
  • ART 驗證器會回報的一些常見問題包括:
    • 控制流程無效
    • 不平衡 monitorenter/monitorexit
    • 0 長度參數類型清單大小
  • 部分應用程式在已安裝的 .odex 檔案中有依附元件 格式為 /system/framework/data/dalvik-cache 或 位於 DexClassLoader 的最佳化輸出目錄中。這些 檔案現在是 ELF 檔案,而不是 DEX 的擴充檔案。ART 嘗試時 遵循與 Dalvik 相同的命名和鎖定規則,應用程式不應 檔案格式格式如有變更,恕不另行通知。

    注意:在 Android 8.0 (API 級別 26) 中, 較高,則 DexClassLoader 最佳化的輸出目錄 如需詳細資訊,請參閱 DexClassLoader() 建構函式中設定。

報表問題

如果遇到非應用程式 JNI 問題以外的問題,請回報 並透過 Android 開放原始碼計畫 Issue Tracker (網址為 https://code.google.com/p/android/issues/list) 取得解決問題。 在 Google 網頁中加入 "adb bugreport" 和該應用程式的連結 Play 商店 (如有)。或者,如果可以,請附上重現的 APK 問題。請注意,問題 (包括附件) 是公開的 顯示。