きっかけ
Androidの実行ファイルにコンパイルするDexをプロセス内で行うことにより、Androidアプリのビルドを高速化するDexInProcessですが、いつ有効になったりならなかったりするのかがよくわかりません。(詳しい仕組みはわかっていません)
詳しい判定をちょっとソース見たら分かりそうじゃないかなと思って見てみました。
まとめ
- Android Gradle Pluginを2.1.2以上を使っている(この仕様になったのがどのバージョンからなのかは調べられていません) 設定場所:プロジェクト/build.gradleで設定
- Build Tools Versionが23.0.2以上 設定場所:プロジェクト/app/build.gradleで設定
- 自分でdexInProcess falseにしていない
./gradlew clean asseDeb
などでビルドして以下のような警告文が出なければ有効になっている
Running dex as a separate process.
To run dex in process, the Gradle daemon needs a larger heap.
It currently has 520 MB.
For faster builds, increase the maximum heap size for the Gradle daemon to at least 1536 MB.
To do this set org.gradle.jvmargs=-Xmx1536M in the project gradle.properties.
For more information see https://docs.gradle.org/current/userguide/build_environment.html
また警告文が出た場合は、このTo do this set org.gradle.jvmargs=-Xmx1536M in the project gradle.properties.
に従って、
プロジェクト/gradle.propertiesに
org.gradle.jvmargs=-Xmx1536M
を書けばOK(状況によって違うようなので1536Mの部分はコピペしないでください)
ただAndroid Gradle Plugin 2.1.2だと計算にバグがあり、javaMaxHeapSizeを設定していると、gradle.propertiesに記述しても有効にならない場合があるようです。Android Gradle Plugin 2.2で修正されているみたいです。
https://code.google.com/p/android/issues/detail?id=208214
読んでみた
ソースコードを読んでみたらshouldDexInProcessというメソッドで判定しているようです。
https://android.googlesource.com/platform/tools/base/+/028ba07/build-system/builder/src/main/java/com/android/builder/core/DexByteCodeConverter.java#250
/**
* Determine whether to dex in process.
*/
@VisibleForTesting
synchronized boolean shouldDexInProcess(
@NonNull DexOptions dexOptions,
@NonNull Revision buildToolsVersion) {
自分でgradleでdexInProcessを無効に設定していたらそっちを優先する(デフォルトは有効)
if (!dexOptions.getDexInProcess()) {
mIsDexInProcess = false;
return false;
}
Build Tools Versionが23.0.2未満だったら警告文出して無効にする
if (buildToolsVersion.compareTo(DexProcessBuilder.FIXED_DX_MERGER) < 0) {
// We substitute Dex > 23.0.2 with the local implementation.
mLogger.warning("Running dex in-process requires build tools %1$s.\n"
+ "For faster builds update this project to use the latest build tools.",
DexProcessBuilder.FIXED_DX_MERGER.toShortString());
mIsDexInProcess = false;
return false;
}
ちなみにFIXED_DX_MERGERは以下のようになっている
ublic static final Revision FIXED_DX_MERGER = new Revision(23, 0, 2);
あとは自分が動いているVMの最大ヒープサイズ(gradle.propertiesのorg.gradle.jvmargsで設定)と Gradleで以下のように宣言できるjavaMaxHeapSizeを比較して、javaMaxHeapSize以上でないと警告文を出す感じです。
自分のプロセス内でビルドするので、その時にこのヒープサイズが必要になるということだと思いました。
ちなみにjavaMaxHeapSize '4g'
しているとgradle.propertiesにorg.gradle.jvmargs=-Xmx4608M
を記述するように言われました。
dexOptions {
javaMaxHeapSize '4g'
}
// Requested memory for dex.
long requestedHeapSize = parseHeapSize(dexOptions.getJavaMaxHeapSize(), mLogger);
// Approximate heap size requested.
long requiredHeapSizeHeuristic = requestedHeapSize + NON_DEX_HEAP_SIZE;
// Get the approximate heap size that was specified by the user.
// It is important that this be close to the -Xmx value specified, as is is compared with
// the requiredHeapSizeHeuristic, which we suggest the user sets in their gradle.properties.
long maxMemory = 0;
for (MemoryPoolMXBean mpBean: ManagementFactory.getMemoryPoolMXBeans()) {
if (mpBean.getType() == MemoryType.HEAP) {
maxMemory += mpBean.getUsage().getMax();
}
}
// Allow a little extra overhead (50M) as in practice the sum of the heap pools is
// slightly lower than the Xmx setting specified by the user.
final long EXTRA_HEAP_OVERHEAD = 50 * 1024 * 1024;
if (requiredHeapSizeHeuristic > maxMemory + EXTRA_HEAP_OVERHEAD) {
String dexOptionsComment = "";
if (dexOptions.getJavaMaxHeapSize() != null) {
dexOptionsComment = String.format(
" (based on the dexOptions.javaMaxHeapSize = %s)",
dexOptions.getJavaMaxHeapSize());
}
mLogger.warning("\nRunning dex as a separate process.\n\n"
+ "To run dex in process, the Gradle daemon needs a larger heap.\n"
+ "It currently has approximately %1$d MB.\n"
+ "For faster builds, increase the maximum heap size for the "
+ "Gradle daemon to more than %2$s MB%3$s.\n"
+ "To do this set org.gradle.jvmargs=-Xmx%2$sM in the "
+ "project gradle.properties.\n"
+ "For more information see "
+ "https://docs.gradle.org/current/userguide/build_environment.html\n",
maxMemory / (1024 * 1024),
requiredHeapSizeHeuristic / (1024 * 1024),
dexOptionsComment);
mIsDexInProcess = false;
return false;
}
mIsDexInProcess = true;
return true;