缓存 JNI 对象和线程安全(在 Android 中)

2023-11-26

我正在编写一个带有本机线程(pthreads)的 C++ 应用程序,我需要调用一些 Java 方法等。我不确定哪些 JNI 对象可以安全地缓存,即存储在我的 C++ 对象中以供以后使用,可能/可能由不同的线程。我确实知道,如果我的类的方法可以由不同的线程调用,我一定不能缓存 JNIEnv,而是缓存 JavaVM 并通过附加当前线程来获取 JNIEnv。但这是否也意味着我无法缓存从 JNIEnv 获得的任何内容?我需要使用通过以下 JNIEnv 方法获得的对象:

FindClass、GetMethodID、NewObject、NewGlobalRef

这些在线程之间是否保持有效,还是我每次都必须获取新的?如果是后者,有没有一种方法可以在一个本机线程中创建一个对象,并能够在不同的线程中访问同一对象?


JNI 方法如FindClass, GetMethodID, GetFieldID是昂贵的操作,但保证在 JVM 的生命周期内生成相同的结果。由于这些操作非常耗时,因此明智的做法是将结果存储在某个地方以便稍后在本机端重用(这是caching).

JNI 缓存仅考虑这些 JNI 函数调用。如果您想缓存任何其他 C++ 或 Java 对象,这是一个不同的主题。 (只是为了清楚)。

缓存的类、方法和字段不依赖于从中检索它们的线程,因此它们在不同线程中都有效。在获取或设置某个对象的字段时,最多必须执行线程安全操作Set<type>Field or Get<type>Field.

由于 FindClass 返回对class对象,您必须将其转换为全局引用,以保证在检索它的函数结束后重用它。您可以通过使用 NewGlobalReference 来实现此目的:

jclass tmp_double_Class = env->FindClass( "java/lang/Double" ); // Check for exceptions!
double_Class = static_cast<jclass>( env->NewGlobalRef( tmp_double_Class ) );
if( double_Class == NULL )
  return;
env->DeleteLocalRef( tmp_double_Class );

这里有一个全 JNI 缓存主题的示例:

MyJni.cpp:

// Just a shortcut for checking for exceptions
#define CHECK_JNI_EXCEPTION( JNIenv ) \
  if( JNIenv->ExceptionCheck() )\
  {\
    JNIenv->ExceptionClear();\
    return JNI_FALSE;\
  }\
\

// Global variables
jclass    point_Class;
jmethodID point_ctor_Method;
jfieldID  point_x_Field;
jfieldID  point_y_Field;

JNIEXPORT jboolean JNICALL Java_com_company_package_MyClass_nativeInit( JNIEnv * env,
                                                                        jclass   clazz )
{
  // Cache java.lang.Double class, methods and fields
  jclass tmp_point_Class = env->FindClass( "android/graphics/Point" );
  CHECK_JNI_EXCEPTION( env )
  point_Class = static_cast<jclass>( env->NewGlobalRef( tmp_point_Class ) );
  if( point_Class == NULL )
    return JNI_FALSE;
  env->DeleteLocalRef( tmp_point_Class );
  point_ctor_Method = env->GetMethodID( point_Class, "<init>", "(II)V" );
  CHECK_JNI_EXCEPTION( env )
  point_x_Field = env->GetFieldID( point_Class, "x", "I" );
  CHECK_JNI_EXCEPTION( env )
  point_y_Field = env->GetFieldID( point_Class, "y", "I" );
  CHECK_JNI_EXCEPTION( env )
  return JNI_TRUE;
}

MyJni.java:

package com.company.package;

class MyClass {
  // ... All java code here ... 

  // Trigger JNI Caching (could be also done using JNI_OnLoad...)
  private static native void nativeInit();

  static {
    System.loadLibrary( "mylib" );
    nativeInit(); // should check the result
  }
}

玩得开心 ;)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

缓存 JNI 对象和线程安全(在 Android 中) 的相关文章

  • jni.h:没有这样的文件或目录

    我一直在关注本教程 http www java tips org other api tips jni simple example of using the java native interface html 在第 5 步 我从 GCC
  • 奇怪的本机崩溃 - pid:0,tid:0 信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR)

    我在 Android 上遇到了奇怪的崩溃 pid 0 tid 0 gt gt gt com oimvo discdj lt lt lt backtrace 00 pc 000000000001d050 data app com oimvo
  • buildozer android NDK 未下载 Ubuntu

    我使用的是 Ubuntu 16 04 LTS 操作系统 我已经在 python2 和 python3 中安装了 buildozer android sdk 已安装 但 buildozer 在下载 android NDK 时显示错误 请帮我解
  • 使用 android ndk 独立工具链构建 mono (android ndk r8e)

    我正在尝试使用 android ndk 版本 r8e 中的 ndk 独立工具链构建 mono 但我无法完成构建 我像这样设置我的独立环境 export SYSROOT home jeremybell Desktop android ndk
  • 有没有办法防止 Tomcat 在加载的 JNI 库损坏内存时崩溃?

    我们有一个在 Tomcat 7 上运行的 Web 应用程序 它加载一个用 C 编码且由第三方开发的 JNI 库模块 基本上 这个库为我们的网络应用程序提供生物识别技术 我们不能为此使用全 java 解决方案 除了使用 JNI 库模块之外别无
  • 通话过程中是否可以拦截语音数据?

    我计划开发 Android 应用程序 对语音数据进行加密 解密 以便各方可以使用安全通道进行通信 那么问题来了 GSM通话时如何拦截语音 音频数据 可能还是不可能 我应该使用 Android NDK 还是其他东西 在 GSM 中 由于信道特
  • C# 锁定传递给方法的引用 - 不好的做法?

    我有一个类似的方法 public static void DoSomething string param1 string param2 SomeObject o lock o o Things Add param1 o Update et
  • NDK 对静态库中函数的未定义引用

    因此 我尝试在 Android 应用程序的本机代码上使用 libopus 我的 Android mk 文件如下所示 PLATFORM PREFIX opt android ext LOCAL PATH PLATFORM PREFIX lib
  • 如何在Java程序中调用DLL中的方法

    我正在尝试使用 JNA 调用 DLL 中的方法 到目前为止已经使用加载了DLL Runtime getRuntime load myworkspace test dll 该 dll 包含我需要访问的方法 如何在我的 Java 文件中执行 D
  • Android NDK r5b外部构建和supc++链接问题

    我正在尝试在 Ubuntu 10 10 上使用 r5b NDK 为 Android 平台交叉编译我们的 C 代码库 使用 CMake 编译阶段成功 但是在 so 的最终链接阶段 有许多对 libsupc a 文件 我指定链接到的文件 中的符
  • Scala SBT 和 JNI 库

    我正在编写一个简单的应用程序Scala通过以下方式使用 leveldb 数据库leveldbjni图书馆 我的build sbt文件看起来像这样 name Whatever version 1 0 scalaVersion 2 10 2 l
  • 从有符号字符转换为无符号字符然后再转换回来?

    我正在使用 JNI 并有一个 jbyte 类型的数组 其中 jbyte 表示为有符号字符 即范围从 128 到 127 jbyte 表示图像像素 对于图像处理 我们通常希望像素分量的范围为0到255 因此 我想将jbyte值转换为0到255
  • 构建错误:depfile 有多个输出路径 ninja:构建停止:子命令失败

    我在使用需要 CMake 支持的 JNI 代码构建 Java 项目时遇到此错误 该项目使用Android Studio构建 并得到NDK CMake和LLVM的支持 这些是 CMake 使用的以下标志 我实际上使用了作为 C 项目创建的项目
  • 在 Android Studio 中使用预构建的共享库

    我需要在我的 android 项目中使用自定义的预构建共享库 在独立 ndk 上构建为 libdynamic so 我在路径 src main 中创建了一个文件夹 jniLibs 然后在其中创建了 4 个文件夹 即 armeabi arme
  • 如何在Java中计算对象的数字年龄[关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我想知道Java中对象的年龄 当我们使用new关键字时 Java中用户定义的对象被创建 但是什么时候它会被销毁 是跨越JVM的perm
  • C/C++ 通过 Android NDK 在 JNI 中看不到 Java 方法

    我正在尝试从使用 NDK 构建的 C 类文件调用 Java 方法 它不断抛出常见的 未找到非静态方法 错误并导致整个 Android 应用程序崩溃 下面的代码片段 有些东西可能不需要 但我按原样保留它们 因为焦点 问题在于refreshJN
  • 如何通过 JNI 将本机枚举公开给 Java?

    我正在从现有项目导入标头以将端口移植到 Android NDK 在某些情况下 我想在 Java 层使用本机标头中定义的枚举 怎样才能做到这一点呢 理想情况下 我想以某种方式将常量公开给 Java 层 但我没有找到这样做的方法 最明显的可能性
  • Android 从 C++ 端播放原始音频

    我需要能够在 Android 系统的 C 端以自定义文件格式传输音频 我正在致力于移植自定义媒体播放器 并且需要能够打开自定义文件并从中传输音频 这很重要 因为我认为从性能角度来看将整个播放器移植到 JAVA 是不可行的 并且通过 JNI
  • android ndk 多点触控?

    我正在编写一个仅使用本机代码的应用程序 那么ndk中是否可以获取多点触控事件呢 我感觉我已经搜索了整个网络 但什么也没找到 有谁知道如何做到这一点 是的 您可以检查名为native activity查看如何获取输入事件 寻找engine h
  • 时间:2019-03-17 标签:c#ThreadSafeDeepCopy

    我一直在阅读很多其他问题以及大量谷歌搜索 但我一直无法找到明确的解决方案 根据我读过的一些最佳实践 类的静态方法应该创建线程安全的 并且实例成员应该将线程安全留给消费者 我想为该类实现深度复制方法 该类本身还有其他引用类型成员 有没有什么方

随机推荐

  • 创建 shell 脚本以在 Linux 上运行 Java 程序

    我创建了一个同步两个目录内容的java程序 该程序将两个目录的位置作为参数来同步它们 同步信息存储在每个目录内的 JSON 格式文件中 我有一个参考库json simple 1 1 1 jar 我在 Windows 上从 Eclipse 运
  • 带括号和不带括号的方法调用的优先级是什么?

    以前的答案 The answer到类似的question是错的 Ruby 中都没有提到方法调用文档也不在社区维基 不带括号的方法调用 比 高or or似乎比不带括号的方法调用具有较低的优先级 puts false or true 相当于 p
  • 如何使用 async/await 返回 Ajax 结果? [复制]

    这个问题在这里已经有答案了 试图熟悉async await 我在 Chrome 中尝试了以下代码 async function f return await get var result f but result不保存结果 字符串 相反 它
  • 在 R 包中包含命令行脚本

    我有兴趣为我正在编写的名为 Slidify 的 R 包提供命令行界面 它用Rscript我认为这将使其成为跨平台的 脚本存储在子目录中inst slidify 为了从任何目录使用该脚本 我将其路径添加到我的 bash profile就像我在
  • 与特定用户以只读方式共享 GitHub 上的私有 git 存储库

    我终于想学习如何 git 所以我正在 GitHub 上写一篇关于版本控制的相当广泛的论文 我有一个freeGitHub pro 帐户 感谢我的大学 所以我可以添加私人存储库 我需要添加我的主管 以便他可以访问这些文档 但我希望他的 GitH
  • 方法名称是否会编译到 EXE 中?

    做类 方法和变量姓名包含在邮件中将 Windows 应用程序项目编译成 EXE 后 For 混淆 名称越少 逆向工程就越困难 And for 表现 名称更短 访问速度更快 e g 因此 如果方法是通过名称调用的 保留名字short 更好的命
  • 是否可以在控制器内获取当前的 Unity 容器

    我像这样注册了统一容器 var container new UnityContainer container RegisterType
  • 在 Node.js 中管理会话? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 在 Node js 中管理会话变量的最佳方法是什么 有图书馆吗 您可以使用以下方法轻松做到这一点 连接 http senchalabs github com connect Connect
  • 如何为库设置 TypeScript 编译器,以便 Webpack 在依赖项目中删除未使用的模块?

    主题库初步说明 很抱歉占用您的时间让您阅读本文 我写它是为了回答诸如 你在做什么 之类的问题 和 你为什么要这样做 The library由大量辅助函数和类组成 在这方面它与 lodash 类似 检查lodash的结构 但与 lodash
  • Selenium / lxml:获取 xpath

    有没有get xpath方法或在 selenium 或 lxml html 中完成类似操作的方法 我有一种感觉 我在某个地方见过 但在文档中找不到类似的东西 伪代码来说明 browser find element by name searc
  • 在 data.table 的 j 参数中使用“list”

    我正在学习 data table 属性一篇博文 我试图理解 汇总表 短而窄 下的部分 首先将 data frame mtcars 强制转换为 data table gt data lt as data table mtcars gt dat
  • 异步foreach

    C 中有异步 foreach 的方法吗 其中 id s 将由该方法异步处理 而不是使用并行 ForEach This Gets all the ID s IEnumerable
  • 权限拒绝:需要 android.permission.READ_PHONE_STATE

    我正在尝试在 Android 应用程序中检测电话 但在接到电话时收到以下消息 08 23 15 16 04 685 Vodafone VFD 600 Warning 850 BroadcastQueue Permission Denial
  • 导入更多脚本会减慢 python 速度吗?

    只是想知道从其他脚本导入更多函数是否会减慢脚本的速度 一些背景 我有两个脚本 一个比另一个运行得快得多 一个在顶部有一个额外的导入语句 在底部有一个额外的函数 但它是中间的东西 这在运行较慢的脚本之间是相同的 有关您的案例的更多信息 导入
  • before_filter 与 devise

    我正在使用 Devise 的内置功能before filter authenticate user 如果用户未通过之前过滤器 尝试在注销时执行操作 我想在应用程序帮助程序中调用我自己的自定义方法 我可以如何以及在哪里执行此操作 我会在过滤器
  • 在 Chrome 扩展程序中重定向 URL

    访问给定 URL 时 如何在扩展程序中重定向 chrome 例如 当我访问http yahoo com 我希望它重定向到http google com NOTE 这个问题的前一个版本询问是否有任何 Google Chrome 扩展程序可以在
  • Git - 重复提交问题

    我不小心在我的存储库中创建了 未知 的提交 并决定尝试从here git filter branch commit filter if GIT COMMITTER NAME unknown then GIT COMMITTER NAME G
  • Delphi找不到System.dcu;默认路径设置应该是什么?

    每当我尝试编译某些内容时 都会出现此错误 F1027 未找到单元 System pas 或二进制等效项 dcu 安装组件后得到它 删除它 重新安装 RAD studio 但仍然一样 为了修复它 我需要库路径 and 浏览路径 请任何人发布你
  • F# 在实际处理 int64 时假设 int

    正在经历欧拉计划在尝试学习 F 时 我在编写解决方案时偶然发现了一个似乎是类型推断的问题问题3 这是我写的 let rec findLargestPrimeFactor p n if n 1 then p else if n p 0 the
  • 缓存 JNI 对象和线程安全(在 Android 中)

    我正在编写一个带有本机线程 pthreads 的 C 应用程序 我需要调用一些 Java 方法等 我不确定哪些 JNI 对象可以安全地缓存 即存储在我的 C 对象中以供以后使用 可能 可能由不同的线程 我确实知道 如果我的类的方法可以由不同