当前位置: 首页 > news >正文

基于JNI实现调用C++ SDK

基于JNI实现调用C++ SDK

  • 背景
  • 分析
  • 解决
  • 实践

背景

上篇文章总结了几种Java项目调用C/C++ SDK项目方法,在逐一实践、踩坑后,最终还是敲定采用 JNI 方式进行实现。在文章开始的过程,会先大概讲讲笔者遇到的情况,因为封装方式需要根据实际项目而定,可能不太适合于任何人。

分析

如图,这里列举了一个C++项目的头部文件,我们可以看到第一个方法,它返回的是一个GopHandle对象,而这个对象里有什么属性呢?笔者也不得而知,它的具体定义在一个被打包好的动态库里面,而且这里模板函数方式的格式,也让笔者无从下手。

在这里插入图片描述
这里总结了笔者遇到过的一些问题及解决方式:

  • C++模板函数请求的映射:目前通过各种渠道资源的搜索(chatgpt、google等社区)及外部求助,暂时还未找出好的解决方式。

  • 关于std::string &data_root 类型映射 :这个在用JNA实践过程中,在C++实际操作字符串时(如简单的读取值)会出现 invalid memory access 问题。猜测 &data_root 这种方式的传递,JNA传入的时string的地址,而C++ 对于这个地址的访问属于跨内存访问,去掉 & ,C++可正常访问

  • 对象指针的映射:虽然JNA提供了Pointer 指针类,但在实践过程中,这个 Pointer 对 基础类型(int、short、byte)的指针生效。对于对象类类型的指针,需要我们在Java层面,设计一个包含一摸一样的属性的 class 类去对应 C++ 的 结构体或者class 类。

以上图为例子,我们需要设计一个Java版本的 GopHandle类去对应 C++ 的 GopHandle,但GopHandle 封装的一个结构体或类,其中信息不得而知。

解决

这里GitHub找了很Java调用C++ SDK项目作参考,最终还是敲定 JNI 去实现,对于上面遇到的一些问题,也想出了解决思路:

  • 如果C++ 方法返回的指针,可以将其放到中间层,统一转为整形表示。(指针通常被表示为一个64位整数,可以用来存储内存地址。通过将指针转换为整数类型,可以在需要时保存或传递指针的值,而不需要直接操作指针。这点来自GPT,理性看待
  • 传参时,对于指针传参,统一放到中间层,用C去实现,Java还是采用对应的数据类型传输。
  • 关于模板函数的传参,同样统一放到中间层,用C去实现调用。

思路理清了,接下来就是撸代码了,以下是一些可能写得不太好C代码(现学现卖),但是能用。(手动狗头)

实践

  • Java项目里,根据头部文件定义本地方法:SentScore.java
    在这里插入图片描述
  • 生成头部文件
javac -h . SentScore.java
  • 用C 实现头部文件接口,在这里才去真正调用C++接口
  • 注意!!! 在这里对于内存的操作,不属于JVM的管理范畴,需要调用ReleaseStringUTFChars 手动释放内存,才不会有内存泄漏的风险。
  • 如下,是几个方法的例子:
 
#include "SentScore.h"
#include "SentScore.h"#include "SentScoreSDK.h"
#include <vector>#undef __request
#define __request EnglishSentPronsRequestJNIEXPORT jlong JNICALL Java_SentScore_HandleCreate(JNIEnv *env, jclass obj, jstring data, jint num_threads){GopJniHandle *jni = new GopJniHandle(num_threads);if (jni){jboolean is_copy;// 实现Java里String ->  char *const char *data_root = env->GetStringUTFChars(data, &is_copy);// 调用SDKjni->handle = GopHandleCreate<__request>(data_root, num_threads);if (is_copy){// 释放内存env->ReleaseStringUTFChars(data, data_root);}}// 指针转整形return reinterpret_cast<jlong>(jni);
}JNIEXPORT jint JNICALL Java_SentScore_HandleRelease(JNIEnv *env, jclass obj, jlong jni_gop_handle){// 整形转指针auto *jni = reinterpret_cast<GopJniHandle*>(jni_gop_handle);jint ans = 0;if (jni){if (jni->handle){ans = GopHandleRelease<__request>(jni->handle);jni->handle = 0;}delete jni;}return ans;
}JNIEXPORT jint JNICALL Java_SentScore_ThreadHandleStarts(JNIEnv *env, jclass obj, jlong jni_gop_thread_handle, jstring jni_ref, jstring jni_utt, jfloat gop_adjust){auto *thread = reinterpret_cast<GopJniThreadHandle*>(jni_gop_thread_handle);__request request;request.result.gop_adjust = gop_adjust;if (thread && thread->thread){// 把传入的字符串jni_ref 复制到到text_buffCopyString(env, thread->text_buff, jni_ref);request.ref_text = thread->text_buff.data();CopyString(env, thread->text_buff, jni_utt);request.audio_id = thread->text_buff.data();return GopThreadHandleStarts<__request>(thread->thread, request);}else{jboolean a1, b1;const char *a = env->GetStringUTFChars(jni_ref, &a1);const char *b = env->GetStringUTFChars(jni_utt, &b1);request.audio_id = b;request.ref_text = a;if (a1) env->ReleaseStringUTFChars(jni_ref, a);if (b1) env->ReleaseStringUTFChars(jni_utt, b);return GopThreadHandleStarts<__request>(NULL, request);}
}
  • 最后一步,将上面的C代码跟着SDK 一起打包成动态库(.so),然后.so文件放到库路径下,在项目里引用调用。这里采用的框架是SpringBoot,直接在启动类里加加载库路径。
  • 关于库路径,可以打印如下代码进行获取,或者在程序里指定库路径:
System.getProperty("java.library.path")
  • 如果是Linux上,一般默认会库路径会有 /usr/bin,那么我们也可以通过创建软链接方式,把库文件放入库路径里。
    在这里插入图片描述

相关文章:

基于JNI实现调用C++ SDK

基于JNI实现调用C SDK 背景分析解决实践 背景 上篇文章总结了几种Java项目调用C/C SDK项目方法&#xff0c;在逐一实践、踩坑后&#xff0c;最终还是敲定采用 JNI 方式进行实现。在文章开始的过程&#xff0c;会先大概讲讲笔者遇到的情况&#xff0c;因为封装方式需要根据实际…...

计算机组成原理笔记——存储器(静态RAM和动态RAM的区别,动态RAM的刷新, ROM……)

■ 随机存取存储器 ■ 1.随机存取存储器&#xff1a;按存储信息的原理不同分为&#xff1a;静态RAM和动态RAM 2.静态RAM&#xff08;SRAM&#xff09;&#xff1a;用触发器工作原理存储信息&#xff0c;但电源掉电时&#xff0c;存储信息会丢失具有易失性。 3.存储器的基本单元…...

企业计算机服务器locked1勒索病毒数据恢复,locked1勒索病毒解密流程

随着计算机技术的不断发展&#xff0c;越来越多的企业走向数字化办公时代&#xff0c;计算机技术为企业的生产运营提供了有利条件&#xff0c;但也为企业带来了网络安全威胁。在本月&#xff0c;云天数据恢复中心陆续接到很多企业的求助&#xff0c;企业的速达办公软件遭到了lo…...

Session 与 JWT 的对决:谁是身份验证的王者? (下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…...

论文笔记:Confidential Assets

Confidential Assets 描述了一种称为“保密交易”的方案&#xff0c;该方案模糊了所有UTXO的金额&#xff0c;同时保持了不创建或销毁硬币的公共可验证性。进一步将此方案扩展到“保密资产”&#xff0c;一种单一的基于区块链的分类帐可以跟踪多种资产类型的方案。将保密交易扩…...

Docker下搭建MySQL主从复制

目录 主从复制简介 主从复制搭建 主从复制简介 主从复制&#xff0c;是用来建立一个和主数据库完全一样的数据库环境&#xff0c;称为从数据库&#xff1b;主数 据库一般是准实时的业务数据库。 主从复制的作用 做数据的热备。作为后备数据库&#xff0c;主数据库服务器故…...

VBA数据库解决方案第七讲:如何利用Recordset对象打开数据库的数据记录集

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

内部培训平台的系统 PlayEdu搭建私有化内部培训平台

PlayEdu是由白书科技团队多年经营的线上教育系统&#xff0c;专为企业提供的全新企业培训方案 我们的目标是为更多的企业机构搭建私有化内部培训平台&#xff0c;以满足不断增长的培训需求 通过PlayEdu&#xff0c;企业可以有效地组织和管理培训资源&#xff0c;提供高质量的…...

Elasticsearch 相似度评分模型介绍

前言 Elasticsearch 是基于 Lucene 的世界范围内最流行的全文检索框架&#xff0c;其文档相似度算法包含 TF/IDF 和 BM25&#xff0c;从 ES 5.0开始 BM25 算法已经成为 ES 默认的相似度评分模块。 TF-IDF 与 BM25 的区别 TF-IDF 和 BM25 都是计算文本相似性的常用算法。TF-ID…...

视频生成的发展史及其原理解析:从Gen2、Emu Video到PixelDance、SVD、Pika 1.0

前言 考虑到文生视频开始爆发&#xff0c;比如11月份就是文生视频最火爆的一个月 11月3日&#xff0c;Runway的Gen-2发布里程碑式更新&#xff0c;支持4K超逼真的清晰度作品(runway是Stable Diffusion最早版本的开发商&#xff0c;Stability AI则开发的SD后续版本)11月16日&a…...

SQL Server 2016(基本概念和命令)

1、文件类型。 【1】主数据文件&#xff1a;数据库的启动信息。扩展名为".mdf"。 【2】次要&#xff08;辅助&#xff09;数据文件&#xff1a;主数据之外的数据都是次要数据文件。扩展名为".ndf"。 【3】事务日志文件&#xff1a;包含恢复数据库的所有事务…...

Linux C语言 30-套接字操作

Linux C语言 30-套接字操作 本节关键字&#xff1a;C语言 网络通信、套接字操作、TCP、UDP、服务端、客户端 相关C库函数&#xff1a;socket, bind, listen, accept, setsockopt, recv, send, recvfrom, sendto, close 什么是网络通信&#xff1f; 通信是人与人之间通过某种…...

RPC和REST对比

RPC和REST对比 参考学习 RPC 和 REST 之间有什么区别&#xff1f; 当我们对比RPC和REST时&#xff0c;其实是在对比RPC风格的API和REST风格的API&#xff0c;后者通常成为RESTful API。 远程过程调用&#xff08;RPC&#xff09;和 REST 是 API 设计中的两种架构风格。API …...

外包干了2年,技术退步明显。。。

前言 简单的说下&#xff0c;我大学的一个同学&#xff0c;毕业后我自己去了自研的公司&#xff0c;他去了外包&#xff0c;快两年了我薪资、技术各个方面都有了很大的提升&#xff0c;他在外包干的这两年人都要废了&#xff0c;技术没一点提升&#xff0c;学不到任何东西&…...

深度学习——第1章 深度学习的概念及神经网络的工作原理

1.1 序言——探索智能机器 千百年来&#xff0c;人类试图了解智能的机制&#xff0c;并将它复制到思维机器上。 人类从不满足于让机械或电子设备帮助做一些简单的任务&#xff0c;例如使用滑轮吊起沉重的岩石&#xff0c;使用计算器做算术。 人类希望计算机能够自动化执行更…...

爬虫爬取百度图片、搜狗图片

通过以下代码可以爬取两大图片网站&#xff08;百度和搜狗&#xff09;的图片&#xff0c;对于人工智能、深度学习中图片数据的搜集很有帮助&#xff01; 一、爬取百度图片 该代码可以爬取任意百度图片中自定义的图片&#xff1a; import requests import re import time imp…...

Android Camera2使用

一 简介 1.1 Camera API&#xff1a; 这是旧版本的相机API&#xff0c;也称为Camera1 API。它提供了较简单的使用方式&#xff0c;适用于旧版Android设备。但它存在一些限制&#xff0c;如性能不佳、操作复杂等 1.2 Camera2 API&#xff1a; 这是新版本的相机API&#xff0…...

IOS/安卓+charles实现抓包(主要解决证书网站无法打开问题)

安装 官网下载 https://www.charlesproxy.com/latest-release/download.do 安装charles文档 流程 上述链接解决下图问题 使用介绍 Charles介绍 上述链接看一至三即可&#xff0c;了解首页各个按钮的作用 charles全面使用教程及常见功能详解&#xff08;较详细&#xff09…...

七、Lua字符串

文章目录 一、字符串&#xff08;一&#xff09;单引号间的一串字符&#xff08;二&#xff09;local str "Hello, "&#xff08;三&#xff09;[[ 与 ]] 间的一串字符&#xff08;四&#xff09;例子 二、字符串长度计算&#xff08;一&#xff09;string.len&…...

0基础学java-day13

一、包装类 1. 包装类的分类 1) 针对八种基本数据类型相应的引用类型【对象】—包装类 2) 有了类的特点&#xff0c;就可以调用类中的方法。 3) 如图: 2 包装类和基本数据的转换 3 案例演示 Integer01.java package com.hspedu.wrapper;/*** author 林然* version 1.0*/ p…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)

宇树机器人多姿态起立控制强化学习框架论文解析 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架&#xff08;一&#xff09; 论文解读&#xff1a;交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...