安装应用程序需要几分钟的 dex2oat 警告 [英] Installing app takes minutes with dex2oat warnings

查看:86
本文介绍了安装应用程序需要几分钟的 dex2oat 警告的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have re-opened an Android Studio project after quite some time, and I'm seeing fast builds as usual, but now the "Install" step from Android Studio (3.5) is taking minutes, while it used to take seconds.

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

If I open the device Logcat while installing, I can see a huge amount of these:

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)

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

All methods seem to be processed twice (at least) and the garbage collector seems to be doing a lot of work.

我不知道发生了什么,但我很想拥有如此快的速度 - 现在开发是不可能的.有人可以帮忙吗?

I don't know what happened, but I would love to have this fast as it was - right now developing is impossible. Can anyone help?

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

Before dex2oat starts this very long process, I can see the following logs:

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 的一部分.这是一个多模块项目,但其他文件非常相似.

Build file

This is part of build.gradle for the app module. This is a multi-module project, but the other files are very similar.

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 时的输出很大,只粘贴相关部分:

aapt output when using vmSafeMode="true"

Output when running ./Library/Android/sdk/build-tools/29.0.2/aapt list -a app-debug.apk is huge, pasting only the relevant part:

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")

推荐答案

Intro

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

Intro

On device cache build at install time (using dex2oat) i.e. after the app has been built on your build machine:

这是 W/dex2oat:方法处理多次: 警告来自 android.googlesource 文件verification_results.cc 方法 WriterMutexLock mu().

  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:调查我们为什么要为这个方法再次做这项工作并尽量避免它.

很有趣,似乎谷歌知道,有点.

is interesting, seems Google know about it, somewhat.

这条信息消息也很有趣:

This Info message is also interesting:

I/dex2oat:大型应用程序,接受以交换方式运行.

I/dex2oat: Large app, accepted running with swap.

表明dex2oat 检测到一个大型应用程序,并且将要交换 (交换 非常慢,RAM 复制到存储,然后再返回.

This suggests the dex2oat has detected a large app, and is going to swap (swapping is VERY slow, RAM copied to storage, and back again).

精简您的应用程序!请参阅缩小应用大小.

Slim down your app! See Reduce your app size.

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

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

ref2android:vmSafeMode

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

Indicates whether the app would like the virtual machine (VM) to operate in safe mode. The default value is "false".

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

This attribute was added in API level 8 where a value of "true" disabled the Dalvik just-in-time (JIT) compiler.

此属性在 API 级别 22 中进行了调整,其中值为true"禁用了 ART 提前 (AOT) 编译器.当 vmSafeMode 是设置为 true 此过程将使用以下内容执行论点:

This attribute was adapted in API level 22 where a value of "true" disabled the ART ahead-of-time (AOT) compiler. When vmSafeMode is set to true this process will be executed with the following argument:

(3) 使用 adb shell 后期手动插入参数:

(3) Late manual argument insertion with 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) 移除任务

尝试通过关闭不需要的应用程序(或使用类似 绿色化).

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

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

Another method for determining if vmSafeMode is set for a given APK is to use the aapt.exe tool. You will find the aapt tool in the build-tools folder of the Android SDK, which differs in location based on your chosen OS. You will probably have several different versions installed and will find it in a location such as:

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

执行列表命令:

aapt list -a myapkfile.apk

这应该产生的输出包括:

This should produce output including:

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 警告的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆