我在相当长的一段时间后重新打开了一个 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")
最佳答案
简介
在设备上 安装时缓存构建(使用 dex2oat ),即应用程序之后在您的构建机器上构建:
dex2oat 警告
这是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: Investigate why are we doing the work again for this method and try to avoid it.
很有趣,谷歌似乎对此有所了解。
这条信息消息也很有趣:
I/dex2oat: Large app, accepted running with swap.
这表明 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
Indicates whether the app would like the virtual machine (VM) to operate in safe mode. The default value is "false".
This attribute was added in API level 8 where a value of "true" disabled the Dalvik just-in-time (JIT) compiler.
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 totrue
this process will be executed with the following argument:
(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。
调试
Another method for determining if
vmSafeMode
is set for a givenAPK
is to use theaapt.exe
tool. You will find theaapt tool
in thebuild-tools
folder of theAndroid 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
这应该产生输出,包括:
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---------+
关于android - 安装应用程序需要几分钟时间,并出现 dex2oat 警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58027762/