Skip to content

Commit bb2068b

Browse files
committed
[Java.Interop] Log JavaObject lifetimes
Previously, JniRuntime.JniObjectReferenceManager was used to track JNI *reference* lifetimes, but it wasn't used to track *JavaObject* lifetimes, e.g. when a JavaObject instance was created, disposed, or finalized. Xamarin.Android *does* log these events. Update JniRuntime.JniValueMarshaler to log these JavaObject lifetime events, in the spirit of Xamarin.Android but with more information. Update JniRuntime.JniObjectReferenceManager to add properties for whether logging is performed: partial class JniObjectReferenceManager { public virtual bool LogLocalReferenceMessages {get;} public virtual bool LogGlobalReferenceMessages {get;} } This is used by JniRuntime.JniValueMarshaler to avoid possibly expensive Reflection calls when the information won't be logged.
1 parent a673faf commit bb2068b

File tree

3 files changed

+53
-0
lines changed

3 files changed

+53
-0
lines changed

src/Java.Interop/Java.Interop/JniRuntime.JniObjectReferenceManager.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ public virtual int WeakGlobalReferenceCount {
3535
get {return wgrefc;}
3636
}
3737

38+
public virtual bool LogLocalReferenceMessages {
39+
get {return false;}
40+
}
41+
3842
public virtual void WriteLocalReferenceLine (string format, params object[] args)
3943
{
4044
}
@@ -108,6 +112,10 @@ public virtual IntPtr ReleaseLocalReference (ref JniObjectReference reference, r
108112
return h;
109113
}
110114

115+
public virtual bool LogGlobalReferenceMessages {
116+
get {return false;}
117+
}
118+
111119
public virtual void WriteGlobalReferenceLine (string format, params object[] args)
112120
{
113121
}

src/Java.Interop/Java.Interop/JniRuntime.JniValueMarshaler.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
using System.Runtime.CompilerServices;
56

67
namespace Java.Interop
78
{
@@ -115,6 +116,16 @@ internal TCleanup SetObjectPeerReference<T, TCleanup> (T value, ref JniObjectRef
115116

116117
value.IdentityHashCode = JniSystem.IdentityHashCode (newRef);
117118

119+
var o = Runtime.ObjectReferenceManager;
120+
if (o.LogGlobalReferenceMessages) {
121+
o.WriteGlobalReferenceLine ("Created PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}, Java.Type={4}",
122+
newRef.ToString (),
123+
value.IdentityHashCode.ToString ("x"),
124+
RuntimeHelpers.GetHashCode (value).ToString ("x"),
125+
value.GetType ().FullName,
126+
JniEnvironment.Types.GetJniTypeNameFromInstance (newRef));
127+
}
128+
118129
if ((options & DoNotRegisterTarget) != DoNotRegisterTarget) {
119130
RegisterObject (value);
120131
}
@@ -130,6 +141,17 @@ internal void DisposeObject<T> (T value)
130141

131142
if (value.Registered)
132143
UnRegisterObject (value);
144+
145+
var o = Runtime.ObjectReferenceManager;
146+
if (o.LogGlobalReferenceMessages) {
147+
o.WriteGlobalReferenceLine ("Disposing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3} Java.Type={4}",
148+
h.ToString (),
149+
value.IdentityHashCode.ToString ("x"),
150+
RuntimeHelpers.GetHashCode (value).ToString ("x"),
151+
value.GetType ().ToString (),
152+
JniEnvironment.Types.GetJniTypeNameFromInstance (h));
153+
}
154+
133155
value.Dispose (disposing: true);
134156
#if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES
135157
var lref = value.PeerReference.SafeHandle as JniLocalReference;
@@ -148,11 +170,19 @@ internal void TryCollectObject<T> (T value)
148170
where T : IJavaPeerable, IJavaPeerableEx
149171
{
150172
var h = value.PeerReference;
173+
var o = Runtime.ObjectReferenceManager;
151174
// MUST NOT use SafeHandle.ReferenceType: local refs are tied to a JniEnvironment
152175
// and the JniEnvironment's corresponding thread; it's a thread-local value.
153176
// Accessing SafeHandle.ReferenceType won't kill anything (so far...), but
154177
// instead it always returns JniReferenceType.Invalid.
155178
if (!h.IsValid || h.Type == JniObjectReferenceType.Local) {
179+
if (o.LogGlobalReferenceMessages) {
180+
o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}",
181+
h.ToString (),
182+
value.IdentityHashCode.ToString ("x"),
183+
RuntimeHelpers.GetHashCode (value).ToString ("x"),
184+
value.GetType ().ToString ());
185+
}
156186
value.Dispose (disposing: false);
157187
value.SetPeerReference (new JniObjectReference ());
158188
return;
@@ -164,6 +194,13 @@ internal void TryCollectObject<T> (T value)
164194
value.SetPeerReference (new JniObjectReference ());
165195
if (value.Registered)
166196
UnRegisterObject (value);
197+
if (o.LogGlobalReferenceMessages) {
198+
o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}",
199+
h.ToString (),
200+
value.IdentityHashCode.ToString ("x"),
201+
RuntimeHelpers.GetHashCode (value).ToString ("x"),
202+
value.GetType ().ToString ());
203+
}
167204
value.Dispose (disposing: false);
168205
} else {
169206
value.SetPeerReference (h);

src/Java.Interop/Tests/Java.Interop/LoggingJniObjectReferenceManagerDecorator.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ static TextWriter GetWriter (string path, string category)
9696
#endif
9797
}
9898

99+
public override bool LogLocalReferenceMessages {
100+
get {return true;}
101+
}
102+
99103
public override void WriteLocalReferenceLine (string format, params object[] args)
100104
{
101105
if (lrefLog == null)
@@ -171,6 +175,10 @@ public override IntPtr ReleaseLocalReference (ref JniObjectReference value, ref
171175
return manager.ReleaseLocalReference (ref value, ref localReferenceCount);
172176
}
173177

178+
public override bool LogGlobalReferenceMessages {
179+
get {return true;}
180+
}
181+
174182
public override void WriteGlobalReferenceLine (string format, params object[] args)
175183
{
176184
if (grefLog == null)

0 commit comments

Comments
 (0)