Skip to content
Merged

canary #7035

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 0 additions & 251 deletions .claude/skills/review-with-fable/SKILL.md

This file was deleted.

12 changes: 6 additions & 6 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.dev"
versionNameSuffix "-dev"
versionCode 100000787
versionName "10.15.1"
versionCode 100000791
versionName "10.16.0"
}
prod {
dimension "environment"
versionCode 100000787
versionName "10.15.1"
versionCode 100000791
versionName "10.16.0"
}
// ストア配信する dev (Canary) と applicationId を分けた、ローカル検証専用のフレーバー。
// ストアの Canary 版を消さずに同居させるためだけに存在し、配信には使わない
Expand All @@ -183,8 +183,8 @@ android {
dimension "environment"
applicationId "me.tinykitten.trainlcd.local"
versionNameSuffix "-local"
versionCode 100000787
versionName "10.15.1"
versionCode 100000791
versionName "10.16.0"
}
}
}
Expand Down
7 changes: 5 additions & 2 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
# ヒープは据え置き。枯渇していたのは Metaspace だけなので、上限を上げるのはそちらに絞る。
org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=1024m
# ヒープは lintVitalAnalyzeRelease がこのプロセス内で並列に走り、2048m では
# `OutOfMemoryError: Java heap space` で止まったため 4096m にしている
# (CI 実測: v10.16.0 の本番ビルドの :expo-modules-core で発生)。
# 引き上げ後のランナー実測値は docs/android-build-workflows.md の「Build memory」を参照。
org.gradle.jvmargs=-Xmx4096m -XX:MaxMetaspaceSize=1024m

# Kotlin コンパイルデーモンの JVM 引数。未指定だと org.gradle.jvmargs をそのまま
# 継承するため、1 プロセスで node_modules 配下の全ネイティブモジュール +
Expand Down
12 changes: 6 additions & 6 deletions android/wearable/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ android {
dimension = "environment"
applicationIdSuffix = ".dev"
versionNameSuffix = "-dev"
versionCode = 100000788
versionName = "10.15.1"
versionCode = 100000792
versionName = "10.16.0"
}
create("prod") {
dimension = "environment"
versionCode = 100000788
versionName = "10.15.1"
versionCode = 100000792
versionName = "10.16.0"
}
// :app の local フレーバーと対になるローカル検証専用フレーバー。Wear の Data Layer は
// applicationId が一致する場合しか疎通しないため、:app を .local にしたときは
Expand All @@ -100,8 +100,8 @@ android {
dimension = "environment"
applicationIdSuffix = ".local"
versionNameSuffix = "-local"
versionCode = 100000788
versionName = "10.15.1"
versionCode = 100000792
versionName = "10.16.0"
}
}

Expand Down
6 changes: 3 additions & 3 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const IS_DEV = process.env.APP_VARIANT === 'dev' || IS_LOCAL;
export default {
name: 'TrainLCD',
slug: 'trainlcd',
version: '10.15.1',
version: '10.16.0',
plugins: [
'expo-image',
'expo-font',
Expand Down Expand Up @@ -57,7 +57,7 @@ export default {
userInterfaceStyle: 'automatic',
// Expo SDK 57 の各モジュール(expo / expo-modules-core ほか)は podspec で iOS 16.4 以上を要求する
deploymentTarget: '16.4',
buildNumber: '2923',
buildNumber: '2925',
scheme: IS_DEV ? 'CanaryTrainLCD' : 'ProdTrainLCD',
bundleIdentifier: IS_DEV
? 'me.tinykitten.trainlcd.dev'
Expand All @@ -71,7 +71,7 @@ export default {
? 'me.tinykitten.trainlcd.dev'
: 'me.tinykitten.trainlcd',
permissions: [],
versionCode: 100000787,
versionCode: 100000791,
},
owner: 'trainlcd',
experiments: {
Expand Down
5 changes: 5 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@
"trainTypeFilterClearAll": "Clear filters",
"trainTypeCount": "%{count} types",
"trainTypeFilterCount": "%{count} of %{total}",
"trainTypeSortHeading": "Sort by",
"trainTypeSortRecommended": "Recommended",
"trainTypeSortArrivalTime": "Earliest arrival",
"trainTypeSortTransferCount": "Fewest transfers",
"trainTypeSortError": "Couldn't sort the list. Showing recommended order.",
"busRoutesNotExist": "No routes available",
"enableNotificationMode": "Arrival notifications",
"betaNotice": "This TrainLCD is currently in beta release.",
Expand Down
5 changes: 5 additions & 0 deletions assets/translations/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@
"trainTypeFilterClearAll": "条件をクリア",
"trainTypeCount": "%{count}件",
"trainTypeFilterCount": "%{total}件中 %{count}件",
"trainTypeSortHeading": "並べ替え",
"trainTypeSortRecommended": "おすすめ順",
"trainTypeSortArrivalTime": "到着が早い順",
"trainTypeSortTransferCount": "乗換が少ない順",
"trainTypeSortError": "並べ替えられなかったため、おすすめ順で表示しています。",
"busRoutesNotExist": "系統がありません",
"enableNotificationMode": "駅到着時に通知",
"betaNotice": "このTrainLCDは現在ベータリリースです。",
Expand Down
53 changes: 40 additions & 13 deletions docs/android-build-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,14 +168,26 @@ real cause.
`android/gradle.properties` therefore raises the Metaspace ceiling and pins the
Kotlin daemon explicitly rather than letting it inherit:

| Property | Heap | Metaspace (before → after) |
| Property | Heap | Metaspace |
| --- | --- | --- |
| `org.gradle.jvmargs` | `-Xmx2048m` | `512m` → `1024m` |
| `kotlin.daemon.jvmargs` | `-Xmx2048m` | inherited `512m` → `1024m` |
| `org.gradle.jvmargs` | `-Xmx4096m` | `1024m` |
| `kotlin.daemon.jvmargs` | `-Xmx2048m` | `1024m` |

**Only the Metaspace ceiling changes.** Both heap ceilings stay at the `2048m`
the build already ran with — it compiled every native module, `:app`, and R8
without a heap OOM, so raising `-Xmx` would treat a symptom the build never had.
The Metaspace ceilings were raised first, from `512m` to `1024m`, when the heap
had not run out yet. The Gradle daemon heap was raised later, from `2048m` to
`4096m`, after the v10.16.0 production build stopped in Android lint:

```text
Execution failed for task ':expo-modules-core:lintVitalAnalyzeRelease'.
> Unexpected failure during lint analysis of ColorTypeConverter.kt
Message: Java heap space
```

`lintVitalAnalyze*` tasks run inside the Gradle daemon, not in the Kotlin
daemon, and `org.gradle.parallel=true` lets several modules' lint tasks run at
once in that one heap. The same task passed in that day's Canary build of the
same code, so the failure depends on how the lint tasks happen to overlap.
Only the Gradle daemon heap changes; the Kotlin daemon keeps `2048m`.

Do not read a heap ceiling as free headroom. Metaspace is committed lazily, so
its ceiling mostly just converts a runaway allocation into a clear error. A heap
Expand All @@ -187,14 +199,29 @@ its own.

This repository is public, so its jobs get the 4-vCPU / 16 GB standard runner
(the 2-vCPU / 8 GB tier applies to private repositories). The ceilings above
total 4 GB of heap and 2 GB of Metaspace — but a ceiling is not a memory
total 6 GB of heap and 2 GB of Metaspace — but a ceiling is not a memory
budget. Gradle worker processes, R8, Node, and each JVM's own native memory
(thread stacks, code cache, direct buffers) all sit on top of those numbers,
and none of that has been measured here. So do not read the difference between
the ceilings and the runner's RAM as available headroom, least of all on the
8 GB tier. Before raising any of these values, measure peak RSS across the
whole build on the runner you actually target, and prefer a larger runner over
ceilings the runner cannot back.
(thread stacks, code cache, direct buffers) all sit on top of those numbers.
So do not read the difference between the ceilings and the runner's RAM as
available headroom, least of all on the 8 GB tier.

Before merging the `4096m` Gradle daemon heap, a Build Android Production
dry-run on `ubuntu-22.04`, already running with that ceiling, sampled
`free -m` and the RSS of every `java` process every 5 seconds through
`./gradlew :app:bundleProdRelease :wearable:bundleProdRelease --no-daemon`
([run 35844360229](https://github.com/TrainLCD/MobileApp/actions/runs/35844360229)):

| Measurement | Peak |
| --- | --- |
| System memory used (`free -m`, 15988 MB total) | 10289 MB |
| RSS of all `java` processes | 9019 MB |
| Gradle daemon RSS, during the lint phase | 5326 MB |
| Kotlin daemon RSS | 2427 MB |
| Swap used at the end of the build | 0 MB |

Before raising any of these values again, repeat that measurement on the runner
you actually target, and prefer a larger runner over ceilings the runner cannot
back.

Keep `kotlin.daemon.jvmargs` set whenever `org.gradle.jvmargs` changes,
otherwise the daemon silently picks up the Gradle value again.
19 changes: 19 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ CLAUDE.md「Security & Configuration Guardrails」に従い、依存更新後に

新しいエントリを上に追加する。

## 2026-09-23 — Android リリースビルドの Gradle デーモンのヒープ上限を 4096m に引き上げ

対象バージョン: v10.16.0 の本番ビルド失敗への対応

### 内容

- v10.16.0 の Build Android Production が `:expo-modules-core:lintVitalAnalyzeRelease` で
`OutOfMemoryError: Java heap space` を出して失敗した。同じ日の Canary ビルドでは同じタスクが通っている。
- lint は Gradle デーモンの中で動き、`org.gradle.parallel=true` で複数モジュールの lint が同じヒープを使う。
そのため lint の重なり方によって 2048m を超えることがある。
- `android/gradle.properties` の `org.gradle.jvmargs` を `-Xmx4096m` に上げた。Kotlin デーモンは 2048m のまま。
- マージ前に、4096m にした状態の dry-run で実測した。ピーク時のメモリ使用量は 16GB 中 10289 MB で、swap は使われていない。
詳細は `docs/android-build-workflows.md` の「Build memory」にある。

### 学び

- #6879 では Metaspace だけが枯渇していたのでヒープを据え置いた。ヒープの上限を決めるときは、
Kotlin のコンパイルだけでなく lint のような Gradle デーモン内のタスクも含めて考える。

## 2026-09-12 — ストア版と同居できる Android の `local` ビルドバリアントを追加

対象バージョン: v10.15.0
Expand Down
Loading
Loading