Skip to content

Commit 8746ec5

Browse files
authored
[NativeAOT] Initialize GC threshold much earlier (#10488)
The threshold value is used by the global reference creation routine to determine whether to [start GC collection][0]: ```csharp if (gc >= JNIEnvInit.gref_gc_threshold) { Logger.Log (LogLevel.Debug, "monodroid-gc", gc + " outstanding GREFs. Performing a full GC!"); System.GC.Collect (); } ``` However, the threshold value was being initialized after we've already invoked some non-trivial managed code in the managed [NativeAOT runtime][1], too late to avoid at least a handful of `System.GC.Collect ()` calls: 09-15 14:37:25.923 10761 10761 D monodroid-gc: 1 outstanding GREFs. Performing a full GC! 09-15 14:37:25.923 10761 10761 D monodroid-gc: 2 outstanding GREFs. Performing a full GC! 09-15 14:37:25.923 10761 10761 D monodroid-gc: 3 outstanding GREFs. Performing a full GC! 09-15 14:37:25.924 10761 10761 D monodroid-gc: 3 outstanding GREFs. Performing a full GC! Fix this by splitting the GC threshold value initialization into a separate method which is invoked as soon as possible from the `JNI_OnLoad` function exported by the NativeAOT application. [0]: https://github.com/dotnet/android/blob/e72bf3626024fd1e27dd9cd26d7f8439bc088e19/src/Mono.Android/Android.Runtime/AndroidRuntime.cs#L178-L195 [1]: https://github.com/dotnet/android/blob/e72bf3626024fd1e27dd9cd26d7f8439bc088e19/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs#L60
1 parent cfe0c61 commit 8746ec5

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ static int JNI_OnLoad (IntPtr vm, IntPtr reserved)
1717
try {
1818
AndroidLog.Print (AndroidLogLevel.Info, "JavaInteropRuntime", "JNI_OnLoad()");
1919
XA_Host_NativeAOT_JNI_OnLoad (vm, reserved);
20+
// This must be called before anything else, otherwise we'll see several spurious GC invocations and log messages
21+
// similar to:
22+
//
23+
// 09-15 14:51:01.311 11071 11071 D monodroid-gc: 1 outstanding GREFs. Performing a full GC!
24+
//
25+
JNIEnvInit.NativeAotInitializeMaxGrefGet ();
26+
2027
LogcatTextWriter.Init ();
2128
return (int) JniVersion.v1_6;
2229
}

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,20 @@ static Type TypeGetType (string typeName) =>
7777
androidRuntime!.TypeManager.RegisterNativeMembers (jniType, type, methods);
7878
}
7979

80-
// NOTE: should have different name than `Initialize` to avoid:
81-
// * Assertion at /__w/1/s/src/mono/mono/metadata/icall.c:6258, condition `!only_unmanaged_callers_only' not met
82-
internal static void InitializeJniRuntime (JniRuntime runtime)
80+
// This must be called by NativeAOT before InitializeJniRuntime, as early as possible
81+
internal static void NativeAotInitializeMaxGrefGet ()
8382
{
84-
androidRuntime = runtime;
8583
gref_gc_threshold = RuntimeNativeMethods._monodroid_max_gref_get ();
8684
if (gref_gc_threshold != int.MaxValue) {
8785
gref_gc_threshold = checked((gref_gc_threshold * 9) / 10);
8886
}
87+
}
88+
89+
// NOTE: should have different name than `Initialize` to avoid:
90+
// * Assertion at /__w/1/s/src/mono/mono/metadata/icall.c:6258, condition `!only_unmanaged_callers_only' not met
91+
internal static void InitializeJniRuntime (JniRuntime runtime)
92+
{
93+
androidRuntime = runtime;
8994
SetSynchronizationContext ();
9095
}
9196

0 commit comments

Comments
 (0)