如何调试:JNI 在应用程序中检测到错误:使用无效的作业 [英] How to debug: JNI DETECTED ERROR IN APPLICATION: use of invalid jobject

查看:50
本文介绍了如何调试:JNI 在应用程序中检测到错误:使用无效的作业的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个 Xamarin Android 项目,但出现以下错误(完整日志 这里)

11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] JNI 在应用程序中检测到错误:使用无效的 jobject 0xd4fd90e011-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] "Thread-1973" prio=10 tid=26 Runnable11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] |group="main" sCount=0 dsCount=0 obj=0x137270a0 self=0xc89d490011-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=0xd4b3a93011-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] |状态=R schedstat=( 310795035 15833156 94 ) utm=24 stm=7 核心=5 HZ=10011-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:410] |堆栈=0xd4a3c000-0xd4a3e000 堆栈大小=1022KB11-07 08:28:09.067: A/art(7164): art/runtime/java_vm_ext.cc:41n0] |持有互斥锁=mutator lock"(共享持有)

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

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

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

应用不会崩溃!!!

我正在设备 Samsung SM-G930F aka Samsung S7 上进行测试,并使用 API 级别 23.该错误也会出现在其他设备上.

我的构建设置:

Xamarin Studio 社区版本 6.1.1(构建 15)安装 UUID:b3096ed4-0118-4e0d-87f4-a1fe79ffc301运行:单声道 4.6.1 (mono-4.6.0-branch-c8sr0/ef43c15)(64 位)GTK+ 2.24.23(罗利主题)套餐版本:406010005NuGet版本:3.4.3.0Xamarin.Profiler未安装苹果开发者工具Xcode 8.1 (11544)建造8B62Xamarin.Mac版本:2.10.0.105(Xamarin Studio 社区)Xamarin.iOS版本:10.0.1.10(Xamarin Studio 社区)哈希:ad1cd42分支:cycle8-sr0-xi构建日期:2016-10-03 15:18:44-0400安卓系统版本:7.0.1.3(Xamarin Studio 社区)Android SDK:/Users/andi/Library/Android/sdk支持的安卓版本:5.0(API 级别 21)6.0(API 级别 23)7.0(API 级别 24)SDK 工具版本:25.2.2SDK平台工具版本:24.0.3SDK 构建工具版本:23.0.1Java SDK:/usrjava版本1.8.0_91"Java(TM) SE 运行时环境(构建 1.8.0_91-b14)Java HotSpot(TM) 64 位服务器 VM(构建 25.91-b14,混合模式)此处提供 Android Designer EPL 代码:https://github.com/xamarin/AndroidDesigner.EPLXamarin 安卓播放器版本:0.6.5位置:/应用程序/Xamarin Android Player.app构建信息版本号:601010015Git 修订版:fa52f02641726146e2589ed86ec4097fbe101888构建日期:2016-09-22 08:03:02-04Xamarin 插件:75d65712af93d54dc39ae4c42b21dfa574859fd6构建车道:monodevelop-lion-cycle8-sr0操作系统Mac OS X 10.12.1Darwin Pentagon.local 16.1.0 达尔文内核版本 16.1.0太平洋夏令时间 2016 年 10 月 13 日星期四 21:26:57根:xnu-3789.21.3~60/RELEASE_X86_64 x86_64

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

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

编辑 2这可以标记为#HeisenBug

理想情况下,您如何调试此类情况与您所遵循的路径非常接近.

您想要做的第一件事是通过 adb 或带有 AndroidEnvironmentBuild Action 的 environment.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/疑难解答/#Global_Reference_Messages

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

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

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

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

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

您可能还注意到,在这些行中有一个 grefc 值.这是指 gref 计数,它是 Xamarin.Android 的总金额.然后,您可以假设 grefwc 值相同,即 wref 计数.让我们在一个小表格中定义它:

  • grefc - gref 计数
  • grefwc - wref 计数

让我们看一下这个语法的例子:

I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L ->来自 Java.Lang.Object.RegisterInstance 的新句柄 0x40517468/L(IJavaObject 实例,IntPtr 值,JniHandleOwnership 转移)I/monodroid-gref(12405): 在 Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)I/monodroid-gref(12405): 在 Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)I/monodroid-gref(12405):在 Java.Lang.Thread+RunnableImplementor..ctor(System.Action 处理程序,布尔可移除)I/monodroid-gref(12405): 在 Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)I/monodroid-gref(12405): 在 Android.App.Activity.RunOnUiThread(System.Action action)I/monodroid-gref(12405):在 Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView textview)I/monodroid-gref(12405):在 Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)I/monodroid-gref(12405): 句柄 0x40517468;key_handle 0x40517468:Java 类型:`mono/java/lang/RunnableImplementor`;MCW 类型:`Java.Lang.Thread+RunnableImplementor`I/monodroid-gref(12405): 处理句柄 0x40517468I/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):在 Java.Lang.Object.Dispose()I/monodroid-gref(12405): 在 Java.Lang.Thread+RunnableImplementor.Run()I/monodroid-gref(12405): 在 Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)I/monodroid-gref(12405): 在 System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr, IntPtr)I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G ->来自 take_weak_global_ref_jni 的新句柄 0xde68f4bf/WI/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni

<块引用>

handle或obj-handle值为JNI句柄值,'/'后的字符为句柄值类型:/L为局部引用,/G为全局引用,/W为弱全局引用.

现在让我们考虑一下这个注意事项来看看各种场景:

# Java 实例由 MCW 创建和包装I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L ->新手柄 0x4066df10/L 来自 ...I/monodroid-gref(27679): 处理 0x4066df10;key_handle 0x4066df10:Java 类型:`android/graphics/drawable/TransitionDrawable`;MCW 类型:`Android.Graphics.Drawables.TransitionDrawable`# 正在执行 GC...I/monodroid-gref(27679):+w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G ->来自 take_weak_global_ref_jni 的新句柄 0xde68f95f/WI/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni# 对象还活着,作为句柄 != null# wref 变回 grefI/monodroid-gref(27679): *try_take_global obj=0x4976f080 ->wref=0xde68f95f 句柄=0x4066df10I/monodroid-gref(27679):+g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W ->来自 take_global_ref_jni 的新句柄 0x4066df10/GI/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni# 对象已死,因为句柄 == null# wref 被释放,没有新的 gref 创建I/monodroid-gref(27679): *try_take_global obj=0x4976f080 ->wref=0xde68f95f 句柄=0x0I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni

您可以在 Xamarin.Android 垃圾收集算法 以准确查看这些句柄何时更改.

既然您已经了解了在各种场景中可以看到哪些模式,它将帮助您弄清楚在您的 无效作业 时发生了什么.

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

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

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

JNI 在应用程序中检测到错误:使用无效的 jobject 0xd4fd90e0

然而,这个 handle 可能会随着问题的不同复制而改变.然而,一旦你有了那个 handle,你就可以使用像 grep 搜索handle 字符串:

0xd4fd90e0

完成此操作后,您可以通过上面的示例代码段查看此 句柄 所处的状态,并在相应区域进行修复.(过早的GC,手动处理对象等)

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

I am working on a Xamarin Android project, and I get the following error (full log 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)

when try to play a movie (custom third party ExoPlayer wrapper library) while in airplane mode. I am not seeking help to find the bug with only this info, but only a way to debug app. When crash appears the debugger is disconnected.

Also I have seen this thread: https://bugzilla.xamarin.com/show_bug.cgi?id=45281 on Xamarin bugzilla, but when I enable GC logs with the following:

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

the app does not crash!!!

I am testing on device Samsung SM-G930F aka Samsung S7 and using API level 23. The error appears also on other devices.

My build setup:

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

EDIT:

With gref enabled log (no crash): https://gist.github.com/sanandrea/b9a837b8c885ac037c4f4bc6e8030d10

Without gref enabled (crash): https://gist.github.com/sanandrea/d2c5c895b4bc15f45381421c9c21b859

EDIT 2 This can be tagged as #HeisenBug

解决方案

Ideally how you would debug this type of situation is very close to the path you are following.

The first thing that you'd want to do is enable gref logs via adb or an environment.txt file with a Build Action of AndroidEnvironment(Note: There are limitations using the latter option - 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

Great! Now we can see the lifetime of respective global references(gref for short). This is a starting point. For future reference in this post, let's define a few items:

  • gref - Global Reference
  • wref - Weak Global Reference

Ideally we want to test this on a physical device as it will have a limit of ~52000 grefs. Whereas an emulator has a limit of 2000 grefs. As you imagine this can be quite troublesome if you cross this line quite quickly(Which you just might).

Next we can follow the convention of four main messages we want to know about:

  • Start with +g+ - gref creation
  • Start with -g- - gref destruction
  • Start with +w+ - wref creation
  • Start with -w- - wref destruction

You might also notice that on these lines there is a grefc value. This refers to the gref count which is the total amount that Xamarin.Android has made. You can then assume the same for the grefwc value being the wref count. Let's define this in a small table:

  • grefc - gref count
  • grefwc - wref count

Let' take a look at an example of this syntax:

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.

Now let's take a look into various scenarios with this note in mind:

# 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

You can see my other answer on the Xamarin.Android Garbage Collection Algorithm to see exactly when these handles get changed.

So now that you have an idea of what patterns you can see during various scenarios, it will help you figure out what is going on at the time of your invalid jobject.

Now is the fun part, but also can be the hardest part:

You need to now replicate the crash while this logging is enabled.

Once you have done that, you need to take the new error message you received and the handle given to you. In your original post it refers to:

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

However it's possible that this handle will change throughout different replications of the issue. However once you have that handle, you can use a tool like grep to search for the handle string:

0xd4fd90e0

Once you've done this, you can take a look at what state this handle is in via the sample snippet above and make a fix in the respective area. (Premature GC, Object manually being disposed, etc)

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

这篇关于如何调试:JNI 在应用程序中检测到错误:使用无效的作业的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆