@@ -94,21 +94,41 @@ public AndroidRuntimeOptions (IntPtr jnienv,
9494 EnvironmentPointer = jnienv ;
9595 ClassLoader = new JniObjectReference ( classLoader , JniObjectReferenceType . Global ) ;
9696 InvocationPointer = vm ;
97- ObjectReferenceManager = new AndroidObjectReferenceManager ( ) ;
97+ ObjectReferenceManager = new ManagedObjectReferenceManager ( ) ;
9898 TypeManager = typeManager ;
9999 ValueManager = valueManager ;
100100 UseMarshalMemberBuilder = false ;
101101 JniAddNativeMethodRegistrationAttributePresent = jniAddNativeMethodRegistrationAttributePresent ;
102102 }
103103 }
104104
105- internal class AndroidObjectReferenceManager : JniRuntime . JniObjectReferenceManager {
106- public override int GlobalReferenceCount {
107- get { return RuntimeNativeMethods . _monodroid_gref_get ( ) ; }
105+ /// <summary>
106+ /// Managed object reference manager that maintains GREF, LREF, and WREF counters
107+ /// entirely in managed code, avoiding P/Invoke overhead. Logging P/Invokes are only
108+ /// called when logging is actually enabled.
109+ /// </summary>
110+ internal class ManagedObjectReferenceManager : JniRuntime . JniObjectReferenceManager {
111+
112+ int _grefc ;
113+ int _weak_grefc ;
114+
115+ public override int GlobalReferenceCount => Volatile . Read ( ref _grefc ) ;
116+
117+ public override int WeakGlobalReferenceCount => Volatile . Read ( ref _weak_grefc ) ;
118+
119+ public override bool LogGlobalReferenceMessages => Logger . LogGlobalRef ;
120+ public override bool LogLocalReferenceMessages => Logger . LogLocalRef ;
121+
122+ public override void WriteLocalReferenceLine ( string format , params object ? [ ] args )
123+ {
124+ RuntimeNativeMethods . _monodroid_gref_log ( "[LREF] " + string . Format ( CultureInfo . InvariantCulture , format , args ) ) ;
125+ RuntimeNativeMethods . _monodroid_gref_log ( "\n " ) ;
108126 }
109127
110- public override int WeakGlobalReferenceCount {
111- get { return RuntimeNativeMethods . _monodroid_weak_gref_get ( ) ; }
128+ public override void WriteGlobalReferenceLine ( string format , params object ? [ ] args )
129+ {
130+ RuntimeNativeMethods . _monodroid_gref_log ( string . Format ( CultureInfo . InvariantCulture , format , args ) ) ;
131+ RuntimeNativeMethods . _monodroid_gref_log ( "\n " ) ;
112132 }
113133
114134 public override JniObjectReference CreateLocalReference ( JniObjectReference value , ref int localReferenceCount )
@@ -117,7 +137,7 @@ public override JniObjectReference CreateLocalReference (JniObjectReference valu
117137
118138 if ( Logger . LogLocalRef ) {
119139 var tname = Thread . CurrentThread . Name ;
120- var tid = Thread . CurrentThread . ManagedThreadId ; ;
140+ var tid = Thread . CurrentThread . ManagedThreadId ;
121141 var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
122142 RuntimeNativeMethods . _monodroid_lref_log_new ( localReferenceCount , r . Handle , ( byte ) 'L' , tname , tid , from , 1 ) ;
123143 }
@@ -129,7 +149,7 @@ public override void DeleteLocalReference (ref JniObjectReference value, ref int
129149 {
130150 if ( Logger . LogLocalRef ) {
131151 var tname = Thread . CurrentThread . Name ;
132- var tid = Thread . CurrentThread . ManagedThreadId ; ;
152+ var tid = Thread . CurrentThread . ManagedThreadId ;
133153 var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
134154 RuntimeNativeMethods . _monodroid_lref_log_delete ( localReferenceCount - 1 , value . Handle , ( byte ) 'L' , tname , tid , from , 1 ) ;
135155 }
@@ -141,7 +161,7 @@ public override void CreatedLocalReference (JniObjectReference value, ref int lo
141161 base . CreatedLocalReference ( value , ref localReferenceCount ) ;
142162 if ( Logger . LogLocalRef ) {
143163 var tname = Thread . CurrentThread . Name ;
144- var tid = Thread . CurrentThread . ManagedThreadId ; ;
164+ var tid = Thread . CurrentThread . ManagedThreadId ;
145165 var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
146166 RuntimeNativeMethods . _monodroid_lref_log_new ( localReferenceCount , value . Handle , ( byte ) 'L' , tname , tid , from , 1 ) ;
147167 }
@@ -152,96 +172,94 @@ public override IntPtr ReleaseLocalReference (ref JniObjectReference value, ref
152172 var r = base . ReleaseLocalReference ( ref value , ref localReferenceCount ) ;
153173 if ( Logger . LogLocalRef ) {
154174 var tname = Thread . CurrentThread . Name ;
155- var tid = Thread . CurrentThread . ManagedThreadId ; ;
175+ var tid = Thread . CurrentThread . ManagedThreadId ;
156176 var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
157177 RuntimeNativeMethods . _monodroid_lref_log_delete ( localReferenceCount - 1 , value . Handle , ( byte ) 'L' , tname , tid , from , 1 ) ;
158178 }
159179 return r ;
160180 }
161181
162- public override bool LogGlobalReferenceMessages => Logger . LogGlobalRef ;
163- public override bool LogLocalReferenceMessages => Logger . LogLocalRef ;
164-
165- public override void WriteLocalReferenceLine ( string format , params object ? [ ] args )
166- {
167- RuntimeNativeMethods . _monodroid_gref_log ( "[LREF] " + string . Format ( CultureInfo . InvariantCulture , format , args ) ) ;
168- RuntimeNativeMethods . _monodroid_gref_log ( "\n " ) ;
169- }
170-
171- public override void WriteGlobalReferenceLine ( string format , params object ? [ ] args )
172- {
173- RuntimeNativeMethods . _monodroid_gref_log ( string . Format ( CultureInfo . InvariantCulture , format , args ) ) ;
174- RuntimeNativeMethods . _monodroid_gref_log ( "\n " ) ;
175- }
176-
177182 public override JniObjectReference CreateGlobalReference ( JniObjectReference value )
178183 {
179- var r = base . CreateGlobalReference ( value ) ;
184+ var r = base . CreateGlobalReference ( value ) ;
185+ int gc = Interlocked . Increment ( ref _grefc ) ;
180186
181- var log = Logger . LogGlobalRef ;
182- var ctype = log ? GetObjectRefType ( value . Type ) : ( byte ) '*' ;
183- var ntype = log ? GetObjectRefType ( r . Type ) : ( byte ) '*' ;
184- var tname = log ? Thread . CurrentThread . Name : null ;
185- var tid = log ? Thread . CurrentThread . ManagedThreadId : 0 ;
186- var from = log ? new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) : null ;
187- int gc = RuntimeNativeMethods . _monodroid_gref_log_new ( value . Handle , ctype , r . Handle , ntype , tname , tid , from , 1 ) ;
188187 if ( gc >= JNIEnvInit . gref_gc_threshold ) {
189188 Logger . Log ( LogLevel . Warn , "monodroid-gc" , gc + " outstanding GREFs. Performing a full GC!" ) ;
190189 System . GC . Collect ( ) ;
191190 }
192191
193- return r ;
194- }
192+ if ( ! Logger . LogGlobalRef )
193+ return r ;
195194
196- static byte GetObjectRefType ( JniObjectReferenceType type )
197- {
198- switch ( type ) {
199- case JniObjectReferenceType . Invalid : return ( byte ) 'I' ;
200- case JniObjectReferenceType . Local : return ( byte ) 'L' ;
201- case JniObjectReferenceType . Global : return ( byte ) 'G' ;
202- case JniObjectReferenceType . WeakGlobal : return ( byte ) 'W' ;
203- default : return ( byte ) '*' ;
204- }
195+ var ctype = GetObjectRefType ( value . Type ) ;
196+ var ntype = GetObjectRefType ( r . Type ) ;
197+ var tname = Thread . CurrentThread . Name ;
198+ var tid = Thread . CurrentThread . ManagedThreadId ;
199+ var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
200+ RuntimeNativeMethods . _monodroid_gref_log_new ( value . Handle , ctype , r . Handle , ntype , tname , tid , from , 1 ) ;
201+
202+ return r ;
205203 }
206204
207205 public override void DeleteGlobalReference ( ref JniObjectReference value )
208206 {
209- var log = Logger . LogGlobalRef ;
210- var ctype = log ? GetObjectRefType ( value . Type ) : ( byte ) '*' ;
211- var tname = log ? Thread . CurrentThread . Name : null ;
212- var tid = log ? Thread . CurrentThread . ManagedThreadId : 0 ;
213- var from = log ? new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) : null ;
214- RuntimeNativeMethods . _monodroid_gref_log_delete ( value . Handle , ctype , tname , tid , from , 1 ) ;
207+ Interlocked . Decrement ( ref _grefc ) ;
208+
209+ if ( Logger . LogGlobalRef ) {
210+ var ctype = GetObjectRefType ( value . Type ) ;
211+ var tname = Thread . CurrentThread . Name ;
212+ var tid = Thread . CurrentThread . ManagedThreadId ;
213+ var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
214+ RuntimeNativeMethods . _monodroid_gref_log_delete ( value . Handle , ctype , tname , tid , from , 1 ) ;
215+ }
215216
216217 base . DeleteGlobalReference ( ref value ) ;
217218 }
218219
219220 public override JniObjectReference CreateWeakGlobalReference ( JniObjectReference value )
220221 {
221222 var r = base . CreateWeakGlobalReference ( value ) ;
223+ Interlocked . Increment ( ref _weak_grefc ) ;
224+
225+ if ( ! Logger . LogGlobalRef )
226+ return r ;
222227
223- var log = Logger . LogGlobalRef ;
224- var ctype = log ? GetObjectRefType ( value . Type ) : ( byte ) '*' ;
225- var ntype = log ? GetObjectRefType ( r . Type ) : ( byte ) '*' ;
226- var tname = log ? Thread . CurrentThread . Name : null ;
227- var tid = log ? Thread . CurrentThread . ManagedThreadId : 0 ;
228- var from = log ? new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) : null ;
228+ var ctype = GetObjectRefType ( value . Type ) ;
229+ var ntype = GetObjectRefType ( r . Type ) ;
230+ var tname = Thread . CurrentThread . Name ;
231+ var tid = Thread . CurrentThread . ManagedThreadId ;
232+ var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
229233 RuntimeNativeMethods . _monodroid_weak_gref_new ( value . Handle , ctype , r . Handle , ntype , tname , tid , from , 1 ) ;
230234
231235 return r ;
232236 }
233237
234238 public override void DeleteWeakGlobalReference ( ref JniObjectReference value )
235239 {
236- var log = Logger . LogGlobalRef ;
237- var ctype = log ? GetObjectRefType ( value . Type ) : ( byte ) '*' ;
238- var tname = log ? Thread . CurrentThread . Name : null ;
239- var tid = log ? Thread . CurrentThread . ManagedThreadId : 0 ;
240- var from = log ? new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) : null ;
241- RuntimeNativeMethods . _monodroid_weak_gref_delete ( value . Handle , ctype , tname , tid , from , 1 ) ;
240+ Interlocked . Decrement ( ref _weak_grefc ) ;
241+
242+ if ( Logger . LogGlobalRef ) {
243+ var ctype = GetObjectRefType ( value . Type ) ;
244+ var tname = Thread . CurrentThread . Name ;
245+ var tid = Thread . CurrentThread . ManagedThreadId ;
246+ var from = new StringBuilder ( new StackTrace ( true ) . ToString ( ) ) ;
247+ RuntimeNativeMethods . _monodroid_weak_gref_delete ( value . Handle , ctype , tname , tid , from , 1 ) ;
248+ }
242249
243250 base . DeleteWeakGlobalReference ( ref value ) ;
244251 }
252+
253+ static byte GetObjectRefType ( JniObjectReferenceType type )
254+ {
255+ switch ( type ) {
256+ case JniObjectReferenceType . Invalid : return ( byte ) 'I' ;
257+ case JniObjectReferenceType . Local : return ( byte ) 'L' ;
258+ case JniObjectReferenceType . Global : return ( byte ) 'G' ;
259+ case JniObjectReferenceType . WeakGlobal : return ( byte ) 'W' ;
260+ default : return ( byte ) '*' ;
261+ }
262+ }
245263 }
246264
247265 class AndroidTypeManager : JniRuntime . JniTypeManager {
0 commit comments