Skip to content

build(ci): fix OOM errors on macOS runner#21176

Merged
mikehardy merged 1 commit into
ankidroid:mainfrom
david-allison:oom-2
May 30, 2026
Merged

build(ci): fix OOM errors on macOS runner#21176
mikehardy merged 1 commit into
ankidroid:mainfrom
david-allison:oom-2

Conversation

@david-allison
Copy link
Copy Markdown
Member

...by taking physical memory into account when deciding how many test processes to spawn.

Note

Assisted-by: Claude Opus 4.8 - diagnosis & some code

Purpose / Description

Even though macos-14 has 3 CPUs, there is only 7GB of memory.
Each test process has a max heap of 2GB, with the addition of Gradle this is enough to OOM the machine.

Fixes

Approach

  • Reserve 3GB of RAM for Gradle in our calculations
  • Divide the remaining memory by 2GB per fork
  • Cap the number of works

How Has This Been Tested?

CI-only

Learning (optional, can help others)

  • macos-14 runner. 3 CPUs, 7GB RAM
  • 3GB reserved for Gradle (org.gradle.jvmargs=-Xmx3072M) and the OS
  • 4GB remaining
  • Heap size: 2GB
  • => 2 forks; previously 3

Checklist

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

@david-allison david-allison added the Review High Priority Request for high priority review label May 29, 2026
Copy link
Copy Markdown
Member

@mikehardy mikehardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the approach is solid - question on whether we can make the 3 non-magical

If answer is "nope", then merge at will

If answer is "yep", then after pulling the 3 dynamically, merge away with gusto

Comment thread build.gradle.kts Outdated
if (ciBuild) {
// #21168: The `macos-14` CI runner has only 7GB RAM and OOMs (exit 134) so bound by RAM
val totalRamGb = sysctl("hw.memsize") / (1024 * 1024 * 1024)
val reservedMemory = 3 // 3GB (org.gradle.jvmargs) + OS
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to get that 3GB value dynamically?

concern: we change the 3GB at some point to 4GB (it does creep up over time...) and now we still OOM even with 2 workers because the formula should be kicking out 1 vs 2 ?

Copy link
Copy Markdown
Member Author

@david-allison david-allison May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I chose to parse -Xmx3072M"

Runtime.getRuntime().maxMemory() is dependent on GC flags

GC maxMemory() for -Xmx3072M / GiB (floor)
G1 (JDK 21 default) 3221225472 3
ParallelGC 2863661056 2
SerialGC 3113877504 2

...by taking physical memory into account when deciding how many test
processes to spawn.

Even though `macos-14` has 3 CPUs, there is only 7GB of memory.
Each test process has a max heap of 2GB, with the addition of
Gradle this is enough to OOM the machine.

So we limit the number of test processes based on RAM

`gradleDaemonHeapBytes` is used because
`Runtime.getRuntime().maxMemory()` is GC-dependent
(default => 3GB; ParallelGC => 2GB)

Now:

* 3GB reserved for Gradle (org.gradle.jvmargs=-Xmx3072M) and the OS
* 4GB remaining
* Heap size: 2GB
* => 2 forks

Fixes 21168

Assisted-by: Claude Opus 4.8 - diagnosis & some code
@david-allison
Copy link
Copy Markdown
Member Author

@mikehardy Could I have an approve?

Request changes -> I believe I can only rebase directly, rather than use the merge queue

Copy link
Copy Markdown
Member

@mikehardy mikehardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Runtime.getRuntime().maxMemory() is dependent on GC flags

Why can't anything be easy 😆

Gnarly code but also based on the flag-dependency of the easy way - an optimal solution

And so it goes - nifty fix, thank you!

@mikehardy mikehardy added this pull request to the merge queue May 30, 2026
@mikehardy mikehardy added Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) and removed Review High Priority Request for high priority review Needs Review labels May 30, 2026
Merged via the queue into ankidroid:main with commit bbc2a0f May 30, 2026
20 checks passed
@github-actions github-actions Bot added this to the 2.25 release milestone May 30, 2026
@github-actions github-actions Bot removed the Pending Merge Things with approval that are waiting future merge (e.g. targets a future release, CI wait, etc) label May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: OOM issues on macOS

2 participants