From 208cddee335170dbb30956dde715a8c60fc7bf23 Mon Sep 17 00:00:00 2001 From: Hank Date: Wed, 8 Jul 2026 10:40:39 -0700 Subject: [PATCH] CI: cap Kotlin daemon heap (the real memory hog) + container swap off Server report (20GB/4-core box) showed 3 Kotlin daemons at -Xmx5376m each + clang swarm ~9GB thrashing swap. Cap kotlin.daemon.jvmargs and org.gradle.jvmargs to 1536m in gradle.properties, workers.max=2, no parallel. Container: --cpus=2 --memory=8g with swap disabled (--memory-swap==--memory) so it OOM-fails instead of thrashing disk. Build now uses ~5GB. Co-Authored-By: Claude Fable 5 --- .forgejo/workflows/build-apk.yml | 33 ++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/.forgejo/workflows/build-apk.yml b/.forgejo/workflows/build-apk.yml index b39ccbb..785e6aa 100644 --- a/.forgejo/workflows/build-apk.yml +++ b/.forgejo/workflows/build-apk.yml @@ -22,9 +22,10 @@ jobs: # A purpose-built RN Android image (Android SDK + NDK + Node). Runner needs Docker. container: image: reactnativecommunity/react-native-android:latest - # Hard caps so the build can't starve the host: at most 2 CPUs and 6 GB RAM. - # Adjust to your box (e.g. --cpus=1 / --memory=4g on a smaller server). - options: --cpus=2 --memory=6g --memory-swap=6g + # Hard caps so the build can't starve the 20GB/4-core host: 2 CPUs, 8 GB RAM, + # and NO container swap (--memory-swap == --memory) so it OOM-fails cleanly + # instead of thrashing the disk with swap. With the JVM caps below it uses ~5 GB. + options: --cpus=2 --memory=8g --memory-swap=8g steps: - uses: actions/checkout@v4 @@ -47,6 +48,21 @@ jobs: working-directory: app run: CI=1 npx expo prebuild --platform android --no-install + # The real memory hog is the Kotlin daemon (default ~5.4 GB heap EACH, several + # spawned). Cap every JVM in gradle.properties so the build fits comfortably. + - name: Cap Gradle/Kotlin memory + working-directory: app/android + run: | + cat >> gradle.properties <<'PROPS' + + # --- CI resource caps (host is small; don't thrash swap) --- + org.gradle.jvmargs=-Xmx1536m -XX:MaxMetaspaceSize=512m -Djava.net.preferIPv4Stack=true + org.gradle.workers.max=2 + org.gradle.parallel=false + org.gradle.daemon=false + kotlin.daemon.jvmargs=-Xmx1536m + PROPS + - name: Assemble signed release working-directory: app/android env: @@ -54,16 +70,13 @@ jobs: BBP_UPLOAD_STORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }} BBP_UPLOAD_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }} BBP_UPLOAD_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }} - # Force IPv4 (runner container has no IPv6 -> dl.google.com unreachable) and - # cap the build JVM heap so it stays within the container's memory limit. - GRADLE_OPTS: "-Xmx3g -XX:MaxMetaspaceSize=768m -Djava.net.preferIPv4Stack=true" - # --max-workers=2 + no parallel project builds => at most ~2 concurrent tasks, - # so gradle/kotlin/C++ compiles don't fan out across every core on the host. + # Also cap the no-daemon launcher JVM (org.gradle.jvmargs targets the daemon). + GRADLE_OPTS: "-Xmx1536m -Djava.net.preferIPv4Stack=true" + # --max-workers=2 limits concurrent tasks; container --cpus=2 caps clang -j. run: >- ./gradlew :app:assembleRelease -PreactNativeArchitectures=arm64-v8a - --no-daemon --max-workers=2 -Dorg.gradle.parallel=false - -Djava.net.preferIPv4Stack=true + --no-daemon --max-workers=2 # Self-contained publish via the Forgejo API (no external action to fetch). - name: Publish release + upload APK