【问题标题】:Installing app takes minutes with dex2oat warnings安装应用程序需要几分钟时间并出现 dex2oat 警告
【发布时间】:2019-09-20 11:45:59
【问题描述】:

我在很长一段时间后重新打开了一个 Android Studio 项目,并且我看到像往常一样快速构建,但现在 Android Studio (3.5) 的“安装”步骤需要几分钟,而过去需要几秒钟.

如果我在安装时打开设备 Logcat,我可以看到大量这些:

W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onSaveInstanceState(android.os.Bundle)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onViewCreated(android.view.View, android.os.Bundle)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.onViewModelCreated()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.removeCancelListener(com.package.base.view.BaseDialog$CancelListener)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.removeDismissListener(com.package.base.view.BaseDialog$DismissListener)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setChildFragmentInjector(dagger.android.DispatchingAndroidInjector)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setSharedValue(java.lang.String, java.lang.Object)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseDialog.setViewModelFactory(androidx.lifecycle.ViewModelProvider$Factory)
W/dex2oat: Method processed more than once: dagger.android.AndroidInjector com.package.base.view.BaseDialog.supportFragmentInjector()
I/dex2oat: Explicit concurrent copying GC freed 647(112KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 250.774ms
I/dex2oat: Explicit concurrent copying GC freed 446(29KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 252.704ms
I/dex2oat: Explicit concurrent copying GC freed 396(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 67us total 257.367ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 68us total 258.540ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 64us total 253.988ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 61us total 258.701ms
I/dex2oat: Explicit concurrent copying GC freed 413(13KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 255.313ms
I/dex2oat: Explicit concurrent copying GC freed 419(45KB) AllocSpace objects, 0(0B) LOS objects, 32% free, 12MB/18MB, paused 60us total 261.034ms
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.<init>()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.applyStatusBar(com.package.base.view.BaseFragment$StatusBar)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.dispatchOnStatusBar()
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.restoreStatusBar(android.app.Activity)
W/dex2oat: Method processed more than once: void com.package.base.view.BaseFragment.saveStatusBar(android.app.Activity)

所有方法似乎都被处理了两次(至少),垃圾收集器似乎做了很多工作。

我不知道发生了什么,但我很想拥有这样的速度——现在开发是不可能的。有人可以帮忙吗?

额外信息

在dex2oat开始这个很长的过程之前,我可以看到如下日志:

W/dex2oat: Unexpected CPU variant for X86 using defaults: x86
W/dex2oat: Mismatch between dex2oat instruction set features (ISA: X86 Feature string: -ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt) and those of dex2oat executable (ISA: X86 Feature string: ssse3,-sse4.1,-sse4.2,-avx,-avx2,-popcnt) for the command line:
W/dex2oat: /system/bin/dex2oat --zip-fd=8 --zip-location=base.apk --input-vdex-fd=-1 --output-vdex-fd=10 --oat-fd=9 --oat-location=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA==/oat/x86/base.odex --instruction-set=x86 --instruction-set-variant=x86 --instruction-set-features=default --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=quicken --swap-fd=11 --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]
I/dex2oat: /system/bin/dex2oat --input-vdex-fd=-1 --output-vdex-fd=10 --compiler-filter=quicken --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]
I/dex2oat: Large app, accepted running with swap.

构建文件

这是应用模块build.gradle 的一部分。这是一个多模块项目,但其他文件非常相似。

android {

    compileSdkVersion(AndroidBuild.compileSdk)

    defaultConfig {
        applicationId = "com.package"
        minSdkVersion(AndroidBuild.minSdk)
        targetSdkVersion(AndroidBuild.targetSdk)
        versionCode = 7
        versionName = "0.2.0"
        vectorDrawables.useSupportLibrary = true
        renderscriptTargetApi = 24
        renderscriptSupportModeEnabled = true
        multiDexEnabled = true

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        testInstrumentationRunnerArgument("clearPackageData", "true")
    }

    signingConfigs {
        create("release") {
            // signing stuff
        }
    }

    testOptions {
        // execution = "ANDROIDX_TEST_ORCHESTRATOR"
    }

    buildTypes {
        getByName("release") {
            signingConfig = signingConfigs.getByName("release")
            isShrinkResources = true
            isMinifyEnabled = true
            proguardFile(getDefaultProguardFile("proguard-defaults.txt"))
            proguardFile("proguard-rules.pro")
        }
        getByName("debug") {
            versionNameSuffix = "-debug"
            // Hoping that this should speed up builds due to multidexing
            defaultConfig.minSdkVersion(21)
        }
    }

    dataBinding.isEnabled = true
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
}

使用 vmSafeMode="true" 时的 aapt 输出

运行./Library/Android/sdk/build-tools/29.0.2/aapt list -a app-debug.apk时输出很大,只粘贴相关部分:

E: application (line=57)
  A: android:theme(0x01010000)=@0x7f11014c
  A: android:label(0x01010001)=@0x7f100002
  A: android:icon(0x01010002)=@0x7f0e0001
  A: android:name(0x01010003)="com.package.App" (Raw: "com.package.App")
  A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
  A: android:allowBackup(0x01010280)=(type 0x12)0xffffffff
  A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff
  A: android:supportsRtl(0x010103af)=(type 0x12)0xffffffff
  A: android:appComponentFactory(0x0101057a)="androidx.core.app.CoreComponentFactory" (Raw: "androidx.core.app.CoreComponentFactory")

【问题讨论】:

  • 你能把gradle文件放在这里吗?
  • 你用的是什么手机和安卓版本?你试过其他手机吗?
  • @esentsov 尝试使用 Nexus 5X API 28 和模拟器。它似乎不是特定于设备的。
  • @Mr.AF 如果您告诉我您对哪个部分感兴趣,我可能会粘贴它或简单地回答您。我可以说这是一个支持 MultiDex 的应用程序,如下所述:developer.android.com/studio/build/multidex。
  • Android 标签内

标签: android android-studio dex android-multidex dex2oat


【解决方案1】:

简介

在设备上缓存构建在安装时(使用dex2oat)即在应用程序已经在您的构建机器上构建:

dex2oat 警告

这就是文件verification_results.cc方法WriterMutexLock mu()中android.googlesource中的W/dex2oat: Method processed more than once:警告的来源。

  WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
  auto it = verified_methods_.find(ref);
  if (it != verified_methods_.end()) {
    // TODO: Investigate why are we doing the work again for this method and try to avoid it.
    LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod();
    if (!Runtime::Current()->UseJitCompilation()) {
      DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
      DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
    }
    // Delete the new verified method since there was already an existing one registered. It
    // is unsafe to replace the existing one since the JIT may be using it to generate a
    // native GC map.
    delete verified_method;
    return;
  }

:

// TODO: Investigate why are we doing the work again for this method and try to avoid it.

很有趣,Google 似乎对此有所了解。

这条信息也很有趣:

I/dex2oat:大型应用程序,接受与交换一起运行。

这建议dex2oat 检测到一个大型应用程序,并且将要交换(swapping 非常慢,RAM 复制到存储,然后再返回)。

修复

(1) 减小应用大小

精简您的应用程序!见Reduce your app size。

(2) 禁用 ART

ref1 创建一个新 最小 …/app/src/debug/AndroidManifest.xml 文件:

<manifest
 xmlns:android="http://schemas.android.com/apk/res/android"> 
 <application android:vmSafeMode="true" />
</manifest>

ref2 android:vmSafeMode

指示应用程序是否希望虚拟机 (VM) 在安全模式下运行。默认值为“false”。

此属性是在 API 级别 8 中添加的,其中值为“true” 禁用 Dalvik 即时 (JIT) 编译器。

此属性在 API 级别 22 中进行了调整,其中值为“true” 禁用 ART 提前 (AOT) 编译器。当vmSafeMode 是 设置为true这个过程将执行以下 论据:

(3) 使用adb shell 延迟手动插入参数:

/system/bin/dex2oat ... --compiler-filter=interpret-only

你的跑步:

 /system/bin/dex2oat --zip-fd=8 --zip-location=base.apk --input-vdex-fd=-1 --output-vdex-fd=10 --oat-fd=9 --oat-location=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA==/oat/x86/base.odex --instruction-set=x86 --instruction-set-variant=x86 --instruction-set-features=default --runtime-arg -Xms64m --runtime-arg -Xmx512m --compiler-filter=quicken --swap-fd=11 --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]

和:

 /system/bin/dex2oat --input-vdex-fd=-1 --output-vdex-fd=10 --compiler-filter=quicken --debuggable --classpath-dir=/data/app/com.package-7KbZxh8JQyXUOcSGvv-5hA== --class-loader-context=PCL[]

(4) 删除任务

尝试通过关闭不需要的应用(或使用 Greenify 之类的东西)在安装时最大化您的可用 RAM。

(5) 尝试使用Instant run

  • 仅构建和部署增量更改
  • 不要重新安装应用程序。
  • 不要重启应用。
  • 甚至不要重新启动 Activity。

调试

确定vmSafeMode是否为给定设置的另一种方法 APK 是使用aapt.exe 工具。你会发现aapt tool 在 Android SDK 的 build-tools 文件夹,不同之处在于 位置取决于您选择的操作系统。你可能会有几个 安装不同的版本,并会在以下位置找到它:

.../Android/sdk/build-tools/22.0.1/aapt.exe

执行列表命令:

aapt list -a myapkfile.apk

这应该产生输出,包括:

Android manifest:
N: android=http://schemas.android.com/apk/res/android
  E: manifest (line=17)
    A: android:versionCode(0x0101021b)=(type 0x10)0x1
    A: android:versionName(0x0101021c)="1.0" (Raw: "1.0")
    A: package="com.testing.sample.myapp" (Raw: "com.testing.sample.myapp")
    A: platformBuildVersionCode=(type 0x10)0x16 (Raw: "22")         <---NOTE
    A: platformBuildVersionName="5.1.1-1819727" (Raw: "5.1.1-1819727")
    E: uses-sdk (line=22)
      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x15
      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x16
    E: application (line=26)
      A: android:label(0x01010001)=@0x7f0b0001
      A: android:icon(0x01010002)=@0x7f030000
      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
      A: android:vmSafeMode(0x010102b8)=(type 0x12)0xffffffff
                       ^
                       |
----------NOTE---------+

【讨论】:

  • 我无法减小我的应用程序大小 - 收缩器和其他优化对发布版本起作用,但我的问题是在开发过程中,在调试版本上。我想在调试版本中禁用 dex2oat,但这样做的标志对我不起作用stackoverflow.com/a/58116259/4288782。
  • @natario 如果包含 aapt list -a myapkfile.apk 的结果会很有帮助(请参阅我的调试更新)。跨度>
  • 添加到我的问题中。 vmSafeMode 存在,但 dex2oat 仍在运行(带有交换、警告、延迟和一切)。好像没有设置一样。
  • @natario A: platformBuildVersionCode =(type 0x10)0x16 (Raw: "22") 将与 AndroidBuild.minSdk 的值一起使用i> 和 AndroidBuild.targetSdk 和 compileSdkVersion(AndroidBuild.compileSdk) 在您的 build.gradle 中。大概你使用 apply plugin: 'com.android.application' 而不是 apply plugin: 'com.android.dynamic-feature' 你更新到了 latest 版本的 gradle 和 Android Studio ?你的手机 API 是什么?
  • compileSdk=29, targetSdk=29, minSdk=18, Android Studio 3.5,设备 API 为 27,但这似乎不是特定于设备的。我确实在使用 com.android.application。
【解决方案2】:

首先什么是dex2oat,它适用于Verifying app behavior on the Android runtime (ART),请参阅此链接

https://developer.android.com/guide/practices/verifying-apps-art

现在您需要做的是加快构建过程

您可以禁用此 ART(ahead-of-time) 以优化调试部署并加快构建速度。 由

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
   ...>

 <application
 ...
 android:vmSafeMode="true">
 ...

注意:只有 targetSdkVersion 22+ 才有可能 使用 ART 运行时运行设备。

禁用此功能后,它会减少您的构建时间 更多内容可以参考以下链接https://androidbycode.wordpress.com/2015/07/03/disable-android-art-ahead-of-time-compilation-to-optimize-debug-deployment/

【讨论】:

  • 我已经尝试添加这个标志,但我得到了相同的行为 - 安装缓慢并且所有 dex2oat 日志仍然存在。
  • @natario 是根据您的需要减少构建时间还是花费相同的时间来构建?
  • 它需要相同的时间,所有的警告等等
【解决方案3】:

我有东西可以帮助你 如果您使用的是 windows 在 android studio 中打开终端窗口并输入

gradlew installDebug

或者在linux中放

./gradlew installDebug 

更多信息链接在这里

https://developer.android.com/studio/build/building-cmdline

【讨论】:

    【解决方案4】:

    以下调整可以让事情变得更快(我有 8Go ram,适应你的):

    在 ..\android-studio\bin\studio64.exe.vmoptions

    -Xms2G
    -Xmx4G
    -XX:ReservedCodeCacheSize=580m
    -XX:MetaspaceSize=512m
    

    在 studio.exe.vmoptions 中

    -server
    -Xms1G
    -Xmx2G
    -XX:ReservedCodeCacheSize=480m
    

    【讨论】:

      猜你喜欢
      • 2015-10-30
      • 1970-01-01
      • 2022-09-30
      • 2018-08-17
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 2018-07-06
      • 1970-01-01
      相关资源
      最近更新 更多