Skip to content

Commit 31b44dd

Browse files
Trigger Java GC directly through JNI from C# and remove unnecessary comment
- Call Runtime.gc() directly from C# via JNI instead of calling native code - Remove clr_gc_bridge_trigger_java_gc P/Invoke and native implementation - Remove unnecessary comment from host.cc line 66 - Simplify native GCBridge by removing Runtime instance caching - Regenerate pinvoke-tables.include (now 24 internal p/invokes) Co-authored-by: simonrozsival <374616+simonrozsival@users.noreply.github.com>
1 parent db2dd25 commit 31b44dd

File tree

9 files changed

+27
-65
lines changed

9 files changed

+27
-65
lines changed

src/Mono.Android/Android.Runtime/RuntimeNativeMethods.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ internal unsafe static class RuntimeNativeMethods
9494
internal static extern delegate* unmanaged<MarkCrossReferencesArgs*, void> clr_gc_bridge_initialize_for_managed_processing (
9595
delegate* unmanaged[Cdecl]<MarkCrossReferencesArgs*, void> onMarkCrossReferencesCallback);
9696

97-
/// <summary>
98-
/// Trigger Java garbage collection.
99-
/// </summary>
100-
[DllImport (RuntimeConstants.InternalDllName, CallingConvention = CallingConvention.Cdecl)]
101-
internal static extern void clr_gc_bridge_trigger_java_gc ();
102-
10397
[MethodImplAttribute(MethodImplOptions.InternalCall)]
10498
internal static extern void monodroid_unhandled_exception (Exception javaException);
10599

src/Mono.Android/Microsoft.Android.Runtime/BridgeProcessing.cs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ unsafe class BridgeProcessing
2929
static JniMethodInfo? s_GCUserPeerable_jiAddManagedReference;
3030
static JniMethodInfo? s_GCUserPeerable_jiClearManagedReferences;
3131

32+
// For triggering Java GC directly
33+
static JniObjectReference s_RuntimeInstance;
34+
static JniMethodInfo? s_Runtime_gc;
35+
3236
// Is NativeAOT mode (uses GCUserPeerable instead of IGCUserPeer)
3337
static bool s_initialized;
3438
static bool s_isNativeAOT;
@@ -71,6 +75,14 @@ public static void Initialize (bool isNativeAOT)
7175
s_GCUserPeerable_jiClearManagedReferences = s_GCUserPeerableClass.GetInstanceMethod ("jiClearManagedReferences", "()V");
7276
}
7377

78+
// Initialize Java Runtime for triggering GC
79+
using var runtimeClass = new JniType ("java/lang/Runtime");
80+
var getRuntimeMethod = runtimeClass.GetStaticMethod ("getRuntime", "()Ljava/lang/Runtime;");
81+
s_Runtime_gc = runtimeClass.GetInstanceMethod ("gc", "()V");
82+
var runtimeLocal = JniEnvironment.StaticMethods.CallStaticObjectMethod (runtimeClass.PeerReference, getRuntimeMethod, null);
83+
s_RuntimeInstance = runtimeLocal.NewGlobalRef ();
84+
JniObjectReference.Dispose (ref runtimeLocal);
85+
7486
s_initialized = true;
7587
}
7688

@@ -262,11 +274,19 @@ bool TryCallGCUserPeerableAddManagedReference (JniObjectReference from, JniObjec
262274
}
263275

264276
/// <summary>
265-
/// Trigger Java garbage collection using the cached Runtime instance from native code.
277+
/// Trigger Java garbage collection using the cached Runtime instance directly through JNI.
266278
/// </summary>
267279
static void TriggerJavaGC ()
268280
{
269-
RuntimeNativeMethods.clr_gc_bridge_trigger_java_gc ();
281+
if (s_Runtime_gc == null) {
282+
throw new InvalidOperationException ("BridgeProcessing.Initialize must be called before TriggerJavaGC");
283+
}
284+
285+
try {
286+
JniEnvironment.InstanceMethods.CallVoidMethod (s_RuntimeInstance, s_Runtime_gc, null);
287+
} catch (Exception ex) {
288+
Logger.Log (LogLevel.Error, "monodroid-gc", $"Java GC failed: {ex.Message}");
289+
}
270290
}
271291

272292
void TakeWeakGlobalRef (HandleContext* context)

src/native/clr/host/gc-bridge.cc

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,43 +6,13 @@
66

77
using namespace xamarin::android;
88

9-
void GCBridge::initialize_on_onload (JNIEnv *env) noexcept
9+
void GCBridge::initialize_on_onload ([[maybe_unused]] JNIEnv *env) noexcept
1010
{
11-
abort_if_invalid_pointer_argument (env, "env");
12-
13-
jclass Runtime_class = env->FindClass ("java/lang/Runtime");
14-
abort_unless (Runtime_class != nullptr, "Failed to look up java/lang/Runtime class.");
15-
16-
jmethodID Runtime_getRuntime = env->GetStaticMethodID (Runtime_class, "getRuntime", "()Ljava/lang/Runtime;");
17-
abort_unless (Runtime_getRuntime != nullptr, "Failed to look up the Runtime.getRuntime() method.");
18-
19-
Runtime_gc = env->GetMethodID (Runtime_class, "gc", "()V");
20-
abort_unless (Runtime_gc != nullptr, "Failed to look up the Runtime.gc() method.");
21-
22-
Runtime_instance = OSBridge::lref_to_gref (env, env->CallStaticObjectMethod (Runtime_class, Runtime_getRuntime));
23-
abort_unless (Runtime_instance != nullptr, "Failed to obtain Runtime instance.");
24-
25-
env->DeleteLocalRef (Runtime_class);
11+
// Java Runtime.gc() is now called directly from managed code
2612
}
2713

2814
void GCBridge::initialize_on_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass runtimeClass) noexcept
2915
{
30-
// Bridge processing is now done in managed code (C#)
31-
// No native initialization is needed
32-
}
33-
34-
void GCBridge::trigger_java_gc (JNIEnv *env) noexcept
35-
{
36-
abort_if_invalid_pointer_argument (env, "env");
37-
38-
env->CallVoidMethod (Runtime_instance, Runtime_gc);
39-
if (!env->ExceptionCheck ()) [[likely]] {
40-
return;
41-
}
42-
43-
env->ExceptionDescribe ();
44-
env->ExceptionClear ();
45-
log_error (LOG_DEFAULT, "Java GC failed");
4616
}
4717

4818
void GCBridge::mark_cross_references (MarkCrossReferencesArgs *args) noexcept

src/native/clr/host/internal-pinvokes-shared.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ BridgeProcessingFtn clr_gc_bridge_initialize_for_managed_processing (OnMarkCross
3939
return GCBridge::initialize_for_managed_processing (callback);
4040
}
4141

42-
void clr_gc_bridge_trigger_java_gc () noexcept
43-
{
44-
GCBridge::trigger_java_gc_cached ();
45-
}
46-
4742
void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept
4843
{
4944
switch (level) {

src/native/clr/include/host/gc-bridge.hh

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,21 +65,9 @@ namespace xamarin::android {
6565
return mark_cross_references;
6666
}
6767

68-
static void trigger_java_gc (JNIEnv *env) noexcept;
69-
70-
// Trigger Java GC using the cached Runtime instance (for managed processing mode)
71-
static void trigger_java_gc_cached () noexcept
72-
{
73-
JNIEnv *env = OSBridge::ensure_jnienv ();
74-
trigger_java_gc (env);
75-
}
76-
7768
private:
7869
static inline OnMarkCrossReferencesCallback on_mark_cross_references_callback = nullptr;
7970

80-
static inline jobject Runtime_instance = nullptr;
81-
static inline jmethodID Runtime_gc = nullptr;
82-
8371
static void mark_cross_references (MarkCrossReferencesArgs *args) noexcept;
8472

8573
static void log_mark_cross_references_args_if_enabled (MarkCrossReferencesArgs *args) noexcept;

src/native/clr/include/runtime-base/internal-pinvokes.hh

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ extern "C" {
1818

1919
// Functions for managed GC bridge processing mode
2020
BridgeProcessingFtn clr_gc_bridge_initialize_for_managed_processing (OnMarkCrossReferencesCallback callback) noexcept;
21-
void clr_gc_bridge_trigger_java_gc () noexcept;
2221

2322
void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept;
2423
char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept;

src/native/clr/pinvoke-override/generate-pinvoke-tables.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ const std::vector<std::string> internal_pinvoke_names = {
7070
"clr_typemap_managed_to_java",
7171
"clr_typemap_java_to_managed",
7272
"clr_gc_bridge_initialize_for_managed_processing",
73-
"clr_gc_bridge_trigger_java_gc",
7473
"_monodroid_weak_gref_delete",
7574
"_monodroid_weak_gref_get",
7675
"_monodroid_weak_gref_new",

src/native/clr/pinvoke-override/pinvoke-tables.include

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace {
1212
#if INTPTR_MAX == INT64_MAX
1313
//64-bit internal p/invoke table
14-
std::array<PinvokeEntry, 25> internal_pinvokes {{
14+
std::array<PinvokeEntry, 24> internal_pinvokes {{
1515
{0x34f89602cc44d0, "clr_gc_bridge_initialize_for_managed_processing", reinterpret_cast<void*>(&clr_gc_bridge_initialize_for_managed_processing)},
1616
{0x3b2467e7eadd4a6a, "_monodroid_lref_log_new", reinterpret_cast<void*>(&_monodroid_lref_log_new)},
1717
{0x423c8f539a2c56d2, "_monodroid_lookup_replacement_type", reinterpret_cast<void*>(&_monodroid_lookup_replacement_type)},
@@ -29,7 +29,6 @@ namespace {
2929
{0xb9bae9c43fb05089, "xamarin_app_init", reinterpret_cast<void*>(&xamarin_app_init)},
3030
{0xc2a21d3f6c8ccc24, "_monodroid_lookup_replacement_method_info", reinterpret_cast<void*>(&_monodroid_lookup_replacement_method_info)},
3131
{0xc5b4690e13898fa3, "monodroid_timing_start", reinterpret_cast<void*>(&monodroid_timing_start)},
32-
{0xcb5109712dd7b398, "clr_gc_bridge_trigger_java_gc", reinterpret_cast<void*>(&clr_gc_bridge_trigger_java_gc)},
3332
{0xd1e121b94ea63f2e, "_monodroid_gref_get", reinterpret_cast<void*>(&_monodroid_gref_get)},
3433
{0xd5151b00eb33d85e, "monodroid_TypeManager_get_java_class_name", reinterpret_cast<void*>(&monodroid_TypeManager_get_java_class_name)},
3534
{0xe27b9849b7e982cb, "_monodroid_max_gref_get", reinterpret_cast<void*>(&_monodroid_max_gref_get)},
@@ -544,10 +543,9 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x18
544543
constexpr hash_t system_globalization_native_library_hash = 0x28b5c8fca080abd5;
545544
#else
546545
//32-bit internal p/invoke table
547-
std::array<PinvokeEntry, 25> internal_pinvokes {{
546+
std::array<PinvokeEntry, 24> internal_pinvokes {{
548547
{0xb7a486a, "monodroid_TypeManager_get_java_class_name", reinterpret_cast<void*>(&monodroid_TypeManager_get_java_class_name)},
549548
{0x1d6638a0, "clr_gc_bridge_initialize_for_managed_processing", reinterpret_cast<void*>(&clr_gc_bridge_initialize_for_managed_processing)},
550-
{0x21bee2a0, "clr_gc_bridge_trigger_java_gc", reinterpret_cast<void*>(&clr_gc_bridge_trigger_java_gc)},
551549
{0x2aea7c33, "_monodroid_max_gref_get", reinterpret_cast<void*>(&_monodroid_max_gref_get)},
552550
{0x3227d81a, "monodroid_timing_start", reinterpret_cast<void*>(&monodroid_timing_start)},
553551
{0x333d4835, "_monodroid_lookup_replacement_method_info", reinterpret_cast<void*>(&_monodroid_lookup_replacement_method_info)},
@@ -1077,6 +1075,6 @@ constexpr hash_t system_security_cryptography_native_android_library_hash = 0x93
10771075
constexpr hash_t system_globalization_native_library_hash = 0xa66f1e5a;
10781076
#endif
10791077

1080-
constexpr size_t internal_pinvokes_count = 25;
1078+
constexpr size_t internal_pinvokes_count = 24;
10811079
constexpr size_t dotnet_pinvokes_count = 491;
10821080
} // end of anonymous namespace

src/native/nativeaot/host/host.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ void Host::OnInit (jstring language, jstring filesDir, jstring cacheDir, JnienvI
6363

6464
OSBridge::initialize_on_runtime_init (env, runtimeClass);
6565
GCBridge::initialize_on_runtime_init (env, runtimeClass);
66-
// Bridge processing is now done in managed code (C#)
6766

6867
// We expect the struct to be initialized by the managed land the way it sees fit, we set only the
6968
// fields we support.

0 commit comments

Comments
 (0)