无法执行 JavaVM->DetachCurrentThread():“在运行代码时尝试分离" [英] Can't execute JavaVM->DetachCurrentThread(): "attempting to detach while still running code"

查看:44
本文介绍了无法执行 JavaVM->DetachCurrentThread():“在运行代码时尝试分离"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 NDK 的 Android 应用程序 - 一个具有常规 UI 和 C++ 核心的常规 Android Java 应用程序.在核心中有些地方我需要调用 Java 方法,这意味着我需要该线程的 JNIEnv*,这反过来意味着我需要调用 JavaVM->AttachCurrentThread() 以获取有效的 env.

I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.

以前,只是在做 AttachCurrentThread 并没有费心去分离.它在 Dalvik 中运行良好,但只要调用了 AttachCurrentThread 的线程退出而不调用 DetachCurrentThread,ART 就会中止应用程序.所以我阅读了 JNI 参考,确实它说我必须调用 DetachCurrentThread.但是当我这样做时,ART 会通过以下消息中止应用程序:

Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:

在运行代码时尝试分离

这里有什么问题,如何正确调用DetachCurrentThread?

What's the problem here, and how to call DetachCurrentThread properly?

推荐答案

如果线程没有分离就退出,Dalvik 也会中止.这是通过 pthread 键实现的——参见 Thread.cpp.

Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.

一个线程不能分离,除非它的调用栈是空的.这背后的原因是为了确保在堆栈展开时正确释放任何资源,如监视器锁(即 synchronized 语句).

A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.

根据规范的定义,第二次和后续的附加调用是低成本的无操作.没有引用计数,因此无论发生了多少次附加,分离总是分离.一种解决方案是添加您自己的引用计数包装器.

The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.

另一种方法是每次都附加和分离.这由应用程序框架在某些回调中使用.这并不是一个深思熟虑的选择,而是将 Java 源代码包装在主要用 C++ 开发的代码周围,并试图将功能硬塞进去的副作用.如果您查看 SurfaceTexture.cpp,特别是 JNISurfaceTextureContext::onFrameAvailable(),可以看到当SurfaceTexture需要调用Java语言的回调函数时,它会附加线程,调用回调,然后如果线程刚刚被附加,它会立即将其分离.needsDetach"标志是通过调用 GetEnv 来设置的,以查看线程之前是否已附加.

Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.

这在性能方面并不是一件好事,因为每个附加都需要分配一个线程对象并进行一些内部 VM 内务处理,但它确实会产生正确的行为.

This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.

这篇关于无法执行 JavaVM->DetachCurrentThread():“在运行代码时尝试分离"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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