android - 在集成测试中途遇到 LinearAlloc 溢出

标签 android gradle dalvik

这是一个运行 3-4 年的大型 Android 项目,在 Gradle 5.4.1 上运行。集成测试使用 Mockito、espresso 和 dagger。

我遇到了一个问题,我们将 Pendo 库添加到项目中,依赖项已作为标准添加到 Gradle。一切都运行良好,直到我们尝试运行集成测试(~2000),这些都是用 Spoon 在 fragment 中运行的。

大约在集成测试进行到一半时,在每次随机测试中,由于 LinearAlloc 超出容量,我们都会遇到 native 崩溃而终止测试运行。单独运行这些测试,或者在他们的本地类中运行它们没有问题通过并且已经稳定了很长时间。

我将整个应用程序恢复到已知的良好构建,仅添加了 Pendo 依赖项,这导致了同样的问题,但是我不相信这是由于 Pendo 造成的,因为我通过回到已知的良好构建进行测试(经过测试在这一点上再次出于理智)并添加一个随机的新依赖项,这导致了同样的问题。

据我所知,这可能与 Android 的方法限制有关。我应该提到我们正在使用 multidex 来分解应用程序。 Proguard 和 minify 也在使用中。

这里的部分问题是我真的不确定要查看什么来弄清楚导致此溢出的原因。按照测试运行的日志,似乎没有任何问题,除了一些垃圾收集(我猜这意味着某处泄漏)。我不确定这个问题是否归结为一些潜在的泄漏,并且新库正在将某些东西推到边缘,或者我不知道的 android 中是否存在一些依赖限制,或者其他一些方法来分解文件所以我们不会导致 LinearAlloc 被填满。

从阅读中,我知道 LinearAlloc 的限制在 Android 5 附近有所提高,我们在高于(Android 10)和低于此(Android 4)的设备上都遇到了问题,自 2017 年以来我真的没有看到太多关于这个的聊天,所以我感觉好像我遗漏了一些明显的东西,或者在项目中配置错误,因为它是在那之前设置的。

任何帮助将非常感激。我在下面转储了 gradle 文件的精简版本

android {
    compileSdkVersion 28
    buildToolsVersion "28.0.3"
    sourceSets {
        main.java.srcDirs += "src/main/kotlin"
        main.jniLibs.srcDirs = ["src/main/jni"]
        androidTest.java.srcDirs += ["src/androidTest/kotlin", "src/testUtilities/kotlin"]
        debug.java.srcDirs += "src/debug/kotlin"
        test.java.srcDirs += ["src/test/kotlin", "src/testUtilities/kotlin"]
    }
    defaultConfig {
        minSdkVersion 17
        targetSdkVersion 25 // Required to be sdk 25
        versionCode 94
        versionName "3.4.0"
        versionNameSuffix System.getenv("ANDROID_VERSION_NAME_SUFFIX") ?: ""
        multiDexEnabled true
        multiDexKeepProguard file("multidex-keep-rules.pro")
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        testBuildType "debug"
        renderscriptTargetApi 17
        renderscriptSupportModeEnabled false
        vectorDrawables.useSupportLibrary = true
    }
    packagingOptions {
        exclude "META-INF/ASL2.0"
        exclude "META-INF/LICENSE"
        exclude "META-INF/NOTICE"
        exclude "META-INF/NOTICE.txt"
        exclude "META-INF/LICENSE.txt"
        exclude "META-INF/MANIFEST.MF"
        exclude "META-INF/main.kotlin_module"
        exclude "META-INF/proguard/androidx-annotations.pro"
        exclude "META-INF/atomicfu.kotlin_module"
    }
    buildTypes {
        debug {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            testCoverageEnabled = false
            applicationIdSuffix = '.dev'
            versionNameSuffix "-debug"
            manifestPlaceholders = [isDebug: true]
        }
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            signingConfig signingConfigs.release
            manifestPlaceholders = [isDebug: false]
        }
    }

    dataBinding {
        enabled = true
    }
    testOptions {
        animationsDisabled = true
    }
    lintOptions {
        checkDependencies = false
        checkGeneratedSources = false
        ignoreTestSources = true
        disable "ExpiredTargetSdkVersion"
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

composer {
    variants "debug"
    shard true
    withOrchestrator false
    verboseOutput false
    keepOutput true

    if (project.hasProperty("composerClassTarget")) {
        instrumentationArgument("class", project.getProperty("composerClassTarget"))
    }
}

configurations {
    ktlint
}

task ktlint(type: JavaExec) {
    main = "com.pinterest.ktlint.Main"
    classpath = configurations.ktlint
    args "src/**/*.kt"
}
check.dependsOn ktlint

detekt {
    input = files("$project.projectDir/src")
    config = files("$project.projectDir/detekt.yml")
    filters = ".*/testUtilities/.*, .*build.*, .*/tmp/.*, .*/resources/.*, .*/res/.*"
    parallel = true
}

dependencies {
    ktlint "com.pinterest:ktlint:0.36.0"

    kapt "com.google.dagger:dagger-compiler:$daggerVersion"
    kapt "com.github.bumptech.glide:compiler:$glideVersion"

    kaptAndroidTest "com.google.dagger:dagger-compiler:$daggerVersion"

    implementation fileTree(include: ['**/*.jar'], dir: 'libs')
    implementation "androidx.multidex:multidex:2.0.1"
    implementation "androidx.legacy:legacy-support-v4:1.0.0"
    implementation "androidx.appcompat:appcompat:1.0.2"
    implementation "androidx.recyclerview:recyclerview:1.0.0"
    implementation "androidx.cardview:cardview:1.0.0"
    implementation "androidx.gridlayout:gridlayout:1.0.0"
    implementation "androidx.constraintlayout:constraintlayout:1.1.3"
    implementation "androidx.lifecycle:lifecycle-process:2.2.0"
    implementation "android.arch.work:work-runtime-ktx:$workManagerVersion"
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
    implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutinesVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutinesVersion"
    implementation "io.reactivex.rxjava2:rxkotlin:2.4.0"
    implementation("io.reactivex.rxjava2:rxandroid:2.1.1") {
        exclude group: "io.reactivex.rxjava2", module: "rxjava"
    }
    implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
    implementation "com.squareup.retrofit2:converter-jackson:$retrofitVersion"
    implementation("com.squareup.retrofit2:converter-simplexml:$retrofitVersion") {
        exclude group: "stax", module: "stax-api"
        exclude group: "stax", module: "stax"
        exclude group: "xpp3", module: "xpp3"
    }
    implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
    implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
    implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.9.6"
    implementation "com.clover.sdk:clover-android-sdk:$cloverVersion"
    implementation "com.clover.sdk:clover-android-connector-sdk:$cloverVersion"
    implementation "com.google.dagger:dagger:$daggerVersion"
    implementation "org.slf4j:slf4j-api:$slf4jVersion"
    implementation "com.amazonaws:aws-android-sdk-core:$awsSdkVersion"
    implementation "com.amazonaws:aws-android-sdk-pinpoint:$awsSdkVersion"
    implementation("com.amazonaws:aws-android-sdk-mobile-client:$awsSdkVersion@aar") {
        transitive = true
    }
    implementation "com.amazonaws:aws-android-sdk-s3:$awsSdkVersion"
    implementation "com.amazonaws:aws-android-sdk-appsync:$awsAppSyncSdkVersion"
    implementation "org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0"
    implementation "org.eclipse.paho:org.eclipse.paho.android.service:1.1.1"
    implementation "org.greenrobot:eventbus:3.1.1"
    implementation "com.github.bumptech.glide:glide:$glideVersion"
    implementation "com.github.bumptech.glide:okhttp3-integration:$glideVersion"
    implementation("com.madgag.spongycastle:prov:1.58.0.0") {
        exclude group: "junit"
    }
    implementation "com.auth0.android:jwtdecode:1.4.0"
    implementation "net.grandcentrix.tray:tray:0.12.0"
    implementation "org.threeten:threetenbp:1.4.1"
    implementation("com.jakewharton.threetenabp:threetenabp:1.2.2") {
        exclude module: "threetenbp"
    }
    implementation("com.github.joschi.jackson:jackson-datatype-threetenbp:2.8.4") {
        exclude module: "threetenbp"
    }
    implementation "com.newrelic.agent.android:android-agent:$newRelicVersion"
    implementation "com.journeyapps:zxing-android-embedded:3.6.0"
    implementation "com.g00fy2:versioncompare:1.3.4"
    implementation "com.airbnb.android:lottie:3.3.1"
    implementation project(":app:libs:clover:roam")
    implementation("com.firstdata.clovergo:remote-pay-android-go-connector:3.3.1.4@aar") {
        transitive = true
    }
    implementation('io.branch.sdk.android:library:4.3.2') {
        exclude module: "bbpos"
    }

    debugImplementation "com.squareup.leakcanary:leakcanary-android:$leakCanaryVersion"

    compileOnly "org.glassfish:javax.annotation:10.0-b28"

    runtimeOnly "com.noveogroup.android:android-logger:$androidLoggerVersion"

    testImplementation "org.slf4j:slf4j-simple:$slf4jVersion"
    testImplementation "org.slf4j:jcl-over-slf4j:$slf4jVersion"
    testImplementation "org.hamcrest:hamcrest-junit:2.0.0.0"
    testImplementation("org.mockito:mockito-core:$mockitoVersion") {
        exclude group: "net.bytebuddy"
    }
    testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:$mockitoKotlinVersion") {
        exclude group: "org.jetbrains.kotlin"
        exclude group: "org.mockito"
    }
    testImplementation "net.bytebuddy:byte-buddy-android:$byteBuddyVersion"
    testImplementation "net.bytebuddy:byte-buddy-agent:$byteBuddyVersion"
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutinesVersion"

    androidTestImplementation "androidx.test:runner:1.2.0"
    androidTestImplementation "androidx.test:rules:1.2.0"
    androidTestImplementation "androidx.test.uiautomator:uiautomator:2.2.0"
    androidTestImplementation "androidx.multidex:multidex-instrumentation:2.0.0"
    androidTestImplementation "androidx.test.espresso:espresso-core:$espressoVersion"
    androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") {
        exclude module: "material"
        exclude module: "appcompat"
        exclude module: "recyclerview"
        exclude module: "cardview"
    }
    androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
    androidTestImplementation "android.arch.work:work-testing:$workManagerVersion"
    androidTestImplementation "com.google.dagger:dagger:$daggerVersion"
    androidTestImplementation "org.awaitility:awaitility:3.1.6"
    androidTestImplementation "com.squareup.okhttp3:mockwebserver:$okHttpVersion"
    androidTestImplementation("org.mockito:mockito-android:$mockitoVersion") {
        exclude group: "net.bytebuddy"
    }
    androidTestImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:$mockitoKotlinVersion") {
        exclude group: "org.jetbrains.kotlin"
        exclude group: "org.mockito"
    }
    androidTestImplementation "net.bytebuddy:byte-buddy-android:$byteBuddyVersion"
    androidTestImplementation "net.bytebuddy:byte-buddy-agent:$byteBuddyVersion"
    androidTestImplementation "com.squareup.spoon:spoon-client:1.7.1"
    androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutinesVersion"
}

android.unitTestVariants.all { variant ->
    variant.getRuntimeConfiguration().exclude group: "com.noveogroup.android", module: "android-logger"
}


最佳答案

好的,这是一个有趣的问题,如果有人遇到类似的问题,请留下这个。

在这种情况下,我们发出的错误消息似乎具有相当的误导性。帮助诊断此类错误的一个好方法是查看崩溃留下的墓碑,参见 https://source.android.com/devices/tech/debug/native-crash有关这方面的更多信息

在这种情况下,proguard 是我们的敌人,它似乎对测试代码进行了某种优化,导致变量分配不正确,并通过添加 -optimizations *other optimizations*,!code/allocation/variable 来解决。这可能不适用于您的特定情况,但也许尝试将 proguard 配置为不进行优化,看看是否有帮助:D

关于android - 在集成测试中途遇到 LinearAlloc 溢出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60420269/

相关文章:

java - Fetch:如何添加Listener?

android - setTitle() 在不同时间表现不同

android - 以非零退出值完成 2 BaseGameServices 和 Admob

android - Firebase应用程序分发无法获取应用程序信息:[400]请求包含多个Firebase Android项目设置上的无效参数

android - android中的调用虚拟和调用直接有什么区别

android - AndroidManifest.xml 中没有 <intent-filter> 的 <activity>

android - 初始化逻辑(比如大量单例)应该在 OnCreate 还是 OnResume 中?

Gradle:覆盖插件中的排除配置

android - 在 Android 上,如何制作形状奇特的剪裁区域?

java - 如果类实现较新的接口(interface),Android 推荐的安全支持较新 api 的方法会出错。为什么?