理想情况下,如何调试此类情况非常接近您所遵循的路径.
您要做的第一件事是通过adb或带有AndroidEnvironment构建操作的environment.txt文件启用gref日志(注意:使用后一选项有限制 – https://developer.xamarin.com/guides/android/advanced_topics/environment/#Overview):
adb shell setprop debug.mono.log gref
大!现在我们可以看到各个全局引用的生命周期(简称gref).这是一个起点.为了将来在这篇文章中的参考,让我们定义几个项目:
> gref – 全球参考
> wref – 弱全球参考
理想情况下,我们希望在物理设备上测试它,因为它将具有~52000 grefs的限制.而模拟器的限制为2000 grefs.如你想象的那样,如果你很快就越过这条线(你可能会这样),这可能会非常麻烦.
接下来,我们可以遵循我们想要了解的四条主要消息的惯例:
>从g-gref创建开始
>从-g-开始 – gref销毁
>从w-wref创建开始
>从-w-开始 – wref破坏
您可能还注意到,在这些行上有一个grefc值.这是指gref计数,即Xamarin.Android所做的总量.然后,您可以假设grefwc值为wref计数.让我们在一个小表中定义它:
> grefc – gref count
> grefwc – wref计数
让我们来看看这个语法的一个例子:
I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean removable)
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405): at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405): at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView textview)
I/monodroid-gref(12405): at Mono.Samples.Hello.HelloActivity.m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type: `mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from at Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType handle_type)
I/monodroid-gref(12405): at Java.Lang.Object.Dispose()
I/monodroid-gref(12405): at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405): at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405): at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni
The handle or obj-handle value is the JNI handle value, and the character after the ‘ /’ is the type of handle value: /L for local reference, /G for global references, and /W for weak global references.
现在让我们在考虑这个注意事项的情况下看看各种场景:
# Java instance is created and wrapped by a MCW
I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L -> new-handle 0x4066df10/L from ...
I/monodroid-gref(27679): handle 0x4066df10; key_handle 0x4066df10: Java Type: `android/graphics/drawable/TransitionDrawable`; MCW type: `Android.Graphics.Drawables.TransitionDrawable`
# A GC is being performed...
I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W from take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni
# Object is still alive, as handle != null
# wref turned back into a gref
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x4066df10
I/monodroid-gref(27679): +g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W -> new-handle 0x4066df10/G from take_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni
# Object is dead, as handle == null
# wref is freed, no new gref created
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x0
I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni
现在,您已了解在各种场景中可以看到的模式,它将帮助您了解无效作业时的情况.
现在是有趣的部分,但也可能是最难的部分:
现在,您需要在启用此日志记录时复制崩溃.
完成后,您需要收到收到的新错误消息和给您的句柄.在您的原始帖子中,它指的是:
JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xd4fd90e0
但是,这个句柄可能会在问题的不同复制过程中发生变化.但是,一旦掌握了这个句柄,就可以使用像grep这样的工具来搜索句柄字符串:
0xd4fd90e0
完成此操作后,您可以通过上面的示例代码段查看此句柄的状态,并在相应区域中进行修复. (过早GC,手动处理对象等)