Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Investigation: defer ART collection in the CoreCLR GC bridge

未关闭
#12,436 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

还没有人认领这个 Issue。

评估

难度
5/5
预计耗时
一周以上
新手友好度
30/100
Issue 类型
功能
描述清晰度
需要澄清
活跃度
活跃
技术栈
android, csharp, java

调研方向

从 prototype 中描述的 bridge-round 生命周期开始,并使用 debug.net.gcbridge.explicit_gc=0/1 比较自然 collection 与显式 collection。重现 stress 和 rendering 测量结果,然后评估 overflow 防止、增量 cleanup、resurrection 和 peer reconnection,以及真实设备上的行为。完成的要求是在提出产品变更之前,有证据表明这些风险已得到处理。

由索引模型根据 Issue 内容生成。

描述

Area: CoreCLR Area: Performance needs-triage

Summary

This issue records an experiment evaluating whether the CoreCLR Android GC bridge can avoid synchronously invoking java.lang.Runtime.gc() and instead defer Java peer reclamation until ART runs collection naturally.

The result is promising but not yet production-ready:

  • Deferred collection worked for an 80-minute stress run containing approximately 349,000 Android Callable Wrappers (ACWs).
  • ART naturally reclaimed JNI weak global references (WREFs), allowing the corresponding managed handles to be retired.
  • The WREF table remained below ART's 51,200-entry limit.
  • Avoiding synchronous Runtime.gc() reduced typical bridge time and improved frame pacing in a separate rendering benchmark.
  • The trade-offs were higher memory use, larger retained WREF populations, and worse bridge-time outliers.

This is an investigation report, not yet a proposal to change the product implementation.

Related context:

Prototype design

The prototype changes the bridge lifecycle as follows:

  1. Unreachable Java peers are converted from JNI strong global references (GREFs) to WREFs.
  2. The bridge completes without calling Runtime.gc().
  3. WREFs remain registered across subsequent bridge rounds.
  4. Later rounds probe each WREF using NewLocalRef().
  5. If ART cleared the WREF, the WREF is deleted and its managed handle is released.
  6. Live WREFs are temporarily strengthened only when needed to rebuild the current bridge graph.

A process-wide sweep handles WREFs that are no longer part of the current CoreCLR cross-reference graph.

For comparison, an adb property can enable the old behavior before each sweep:

debug.net.gcbridge.explicit_gc=0  # natural ART collection
debug.net.gcbridge.explicit_gc=1  # invoke Runtime.gc()

The property is read during every bridge round, so both modes use the same APK and runtime implementation.

Stress workload

The test application repeatedly:

  • creates a random component containing 1–1,000 custom ACWs;
  • connects the component into a strongly connected ring with additional random edges;
  • waits 10 ms between individual ACW allocations;
  • drops the only root after completing the component;
  • records managed GC counts, managed heap data, Java heap data, JNI GREF count, RSS, bridge population, reclamation, and phase timings.

Both configurations ran for 10, 20, 40, and finally 80 minutes on the same host-accelerated arm64 emulator using its default ART heap policy. All runs completed without a WREF overflow or fatal runtime error.

80-minute A/B result

Metric Natural ART collection Explicit Runtime.gc()
ACWs allocated 348,659 347,124
Bridge rounds 134 147
Maximum WREFs 35,510 7,616
Final WREFs 27,052 2,437
Handles reclaimed 321,609 343,266
Median bridge algorithm time 9.9 ms 17.3 ms
95th-percentile bridge algorithm time 45.8 ms 21.3 ms
Maximum bridge algorithm time 77.4 ms 22.6 ms
Median Runtime.gc() time — 12.8 ms
Final managed heap size 73.5 MiB 8.8 MiB
Final RSS 255.0 MiB 182.1 MiB

Throughput was intentionally paced by the test and was effectively identical.

Natural collection produced a repeating sawtooth pattern: WREFs accumulated and then fell when ART independently collected their Java referents. The bridge observed 21 reclamation cycles during the natural 80-minute run.

80-minute natural ART timeline

80-minute natural versus explicit ART collection

Natural ART collection is marked at the bridge round that first observed and reclaimed cleared WREFs. Explicit collection timestamps come directly from ART's Explicit concurrent mark compact GC log entries.

Rendering benchmark result

A separate five-minute host-GPU emulator comparison used the application from runtime#131370:

Metric Natural ART collection Explicit Runtime.gc()
Average bridge time 3.1 ms 11.3 ms
Maximum bridge time 18 ms 37 ms
Frames below 55 FPS 2 7
Maximum WREFs 2,465 641

This indicates that removing synchronous ART collection can provide a meaningful typical-latency and frame-pacing improvement. A physical Samsung S23 test also confirmed that ART can naturally clear deferred bridge WREFs under a real 60 FPS workload, although collection was infrequent when Java heap pressure was low.

What we learned

The lifecycle is technically feasible

Keeping peers as WREFs across bridge rounds works. ART can clear them naturally, and the bridge can later detect that state and safely retire the associated managed handles.

It removes a significant synchronous cost

Runtime.gc() directly adds ART collection time to the bridge operation. Avoiding it improved typical bridge duration in both the stress workload and the rendering benchmark.

It exchanges pause time for memory and tail latency

Without explicit collection, more WREFs and managed contexts remain registered. Process-wide probing becomes more expensive as that population grows. The natural run therefore had a better median but substantially worse outliers and higher RSS.

The current diagnostics deliberately scan every registered reference and emit detailed logcat records. They contribute to measured latency, so production measurements without this instrumentation should be better. The underlying sweep is still proportional to the retained WREF population, however.

Natural ART scheduling is not a safety guarantee

ART collected often enough in this stress workload, but applications with little Java allocation pressure can retain WREFs for much longer. The prototype cannot guarantee that ART will collect before its fixed 51,200-entry WREF table fills.

Requirements before considering a product change

  • Provide a hard overflow-prevention strategy instead of relying exclusively on ART scheduling.
  • Make WREF cleanup incremental or otherwise bound the work performed during one bridge round.
  • Validate resurrection and peer-reconnection behavior.
  • Repeat realistic application and physical-device measurements without detailed diagnostic scanning/logging.
  • Evaluate memory and frame-time percentiles across a wider range of workloads and ART implementations.

Current conclusion

Deferred ART collection is worth pursuing. It successfully moves expensive Java collection out of the normal GC bridge path and improves typical bridge latency and frame pacing.

It is not yet safe to ship as-is because reclamation timing is controlled by ART, memory retention is higher, and the current design has no guaranteed protection against WREF-table exhaustion.

主要语言
C#
星标
2.1k
派生
579
平均合并
1 天 10 小时
30 天内合并 PR
215

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 有 Pull Request 模板
  • 没有贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

dotnet/android 的其他 Issue

查看 dotnet/android 的全部 Issue

相似的 Issue

更多 C# Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。