java - 如何调试: JNI DETECTED ERROR IN APPLICATION: use of invalid jobject

标签 java android xamarin xamarin.android

我正在处理一个 Xamarin Android 项目,我收到以下错误(完整日志 here)

11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xd4fd90e0
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] "Thread-1973" prio=10 tid=26 Runnable
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410]   | group="main" sCount=0 dsCount=0 obj=0x137270a0 self=0xc89d4900
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410]   | sysTid=9034 nice=-11 cgrp=default sched=0/0 handle=0xd4b3a930
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410]   | state=R schedstat=( 310795035 15833156 94 ) utm=24 stm=7 core=5 HZ=100
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410]   | stack=0xd4a3c000-0xd4a3e000 stackSize=1022KB
11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:41n0]   | held mutexes= "mutator lock"(shared held)

当尝试在飞行模式下播放电影(自定义第三方 ExoPlayer 包装器库)时。我不是在寻求帮助来仅使用此信息来查找错误,而只是一种调试应用程序的方法。当出现崩溃时,调试器断开连接。

我也看过这个帖子:https://bugzilla.xamarin.com/show_bug.cgi?id=45281 在 Xamarin bugzilla 上,但是当我使用以下内容启用 GC 日志时:

$ adb shell setprop debug.mono.log gref,gc

应用不会崩溃!!!

我正在测试设备 Samsung SM-G930F 又名 Samsung S7 并使用 API 级别 23。该错误也出现在其他设备上。

我的build设置:

Xamarin Studio Community
Version 6.1.1 (build 15)
Installation UUID: b3096ed4-0118-4e0d-87f4-a1fe79ffc301
Runtime:
    Mono 4.6.1 (mono-4.6.0-branch-c8sr0/ef43c15) (64-bit)
    GTK+ 2.24.23 (Raleigh theme)

    Package version: 406010005

NuGet
Version: 3.4.3.0

Xamarin.Profiler
Not Installed

Apple Developer Tools
Xcode 8.1 (11544)
Build 8B62

Xamarin.Mac
Version: 2.10.0.105 (Xamarin Studio Community)

Xamarin.iOS
Version: 10.0.1.10 (Xamarin Studio Community)
Hash: ad1cd42
Branch: cycle8-sr0-xi
Build date: 2016-10-03 15:18:44-0400

Xamarin.Android
Version: 7.0.1.3 (Xamarin Studio Community)
Android SDK: /Users/andi/Library/Android/sdk
    Supported Android versions:
        5.0 (API level 21)
        6.0 (API level 23)
        7.0 (API level 24)

SDK Tools Version: 25.2.2
SDK Platform Tools Version: 24.0.3
SDK Build Tools Version: 23.0.1

Java SDK: /usr
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)

Android Designer EPL code available here:
https://github.com/xamarin/AndroidDesigner.EPL

Xamarin Android Player
Version: 0.6.5
Location: /Applications/Xamarin Android Player.app

Build Information
Release ID: 601010015
Git revision: fa52f02641726146e2589ed86ec4097fbe101888
Build date: 2016-09-22 08:03:02-04
Xamarin addins: 75d65712af93d54dc39ae4c42b21dfa574859fd6
Build lane: monodevelop-lion-cycle8-sr0

Operating System
Mac OS X 10.12.1
Darwin Pentagon.local 16.1.0 Darwin Kernel Version 16.1.0
    Thu Oct 13 21:26:57 PDT 2016
    root:xnu-3789.21.3~60/RELEASE_X86_64 x86_64

编辑:

启用 gref 的日志(无崩溃):https://gist.github.com/sanandrea/b9a837b8c885ac037c4f4bc6e8030d10

未启用 gref(崩溃):https://gist.github.com/sanandrea/d2c5c895b4bc15f45381421c9c21b859

编辑 2 这可以标记为#HeisenBug

最佳答案

理想情况下,您调试此类情况的方式与您所遵循的路径非常接近。

您要做的第一件事是通过 adb 或具有 AndroidEnvironmentBuild Actionenvironment.txt 文件启用 gref 日志(注意:使用后一个选项有限制 - https://developer.xamarin.com/guides/android/advanced_topics/environment/#Overview):

adb shell setprop debug.mono.log gref

https://developer.xamarin.com/guides/android/troubleshooting/troubleshooting/#Global_Reference_Messages

太棒了!现在我们可以看到各个全局引用(简称 gref)的生命周期。这是一个起点。为了以后在这篇文章中引用,让我们定义一些项目:

  • gref - 全局引用
  • wref - 弱全局引用

理想情况下,我们希望在物理设备上对此进行测试,因为它的限制为 ~52000 gref。而模拟器有 2000 个 gref 的限制。正如您想象的那样,如果您很快越过这条线(您可能会这样做),这可能会很麻烦。

接下来我们可以遵循我们想知道的四个主要消息的约定:

  • +g+ 开始 - gref 创建
  • -g-开始——gref销毁
  • +w+开始——wref创建
  • -w-开始-wref销毁

您可能还会注意到在这些行上有一个 grefc 值。这指的是 gref count,它是 Xamarin.Android 产生的总量。然后,您可以假设 grefwc 的值是 wref count。让我们在一个小表中定义它:

  • grefc - gref 计数
  • 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.<OnCreate>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

你可以在Xamarin.Android Garbage Collection Algorithm上看到我的另一个回答以准确查看这些句柄何时更改。

现在您已经了解在各种情况下可以看到哪些模式,它将帮助您弄清楚在您的无效作业时发生了什么。

现在是最有趣的部分,但也可能是最难的部分:

您现在需要在启用此日志记录时复制崩溃。

完成后,您需要获取收到的新错误消息和提供给您的句柄。在您的原始帖子中,它指的是:

JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xd4fd90e0

但是,此句柄 可能会在问题的不同复制过程中发生变化。然而一旦你有了那个句柄,你就可以使用像grep这样的工具了。搜索 handle 字符串:

0xd4fd90e0

完成此操作后,您可以通过上面的示例 fragment 查看此 handle 处于什么状态,并在相应区域进行修复。 (过早的 GC,手动处理对象等)

引用: https://developer.xamarin.com/guides/android/troubleshooting/troubleshooting/#Global_Reference_Messages

关于java - 如何调试: JNI DETECTED ERROR IN APPLICATION: use of invalid jobject,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40508242/

相关文章:

android - 应用程序关闭时,xamarin 的 Plugin.FirebasePushNotification 不起作用

android - MvxAutoCompleteTextView 停留在 'Wait starting for '

java - 如何合并两个android studio项目并使用它?

java - Context 中的 getDrawable (int) 无法应用于 (java.lang.String)

java - 这段从字符串方法解析为整数答案的代码可以吗?

android - 我应该在 BindAdapter 类中使用 inject 吗?

android - 背景在 iOS 上显示,但在 Android Xamarin 上不显示

java - 为什么这个组件不对齐(MigLayout)

java - 使用 setText 方法时出现错误

java - 从 ListView 连接到蓝牙设备