JNI 使用注意事项

c++中获取jbyteArray 的长度并转为char * char * 风格最后有一个 \0,因此必须考虑到。 ================== 参考 http://www.cnblogs.com/lxbblogs/p/3337128.html   jni编程细节 1.mk文件 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) 进行一些变量 阅读详情

前言:

     如果你是为了让Java调用C语言,使用复杂的JNI大可不必,可以选择更简单便捷安全的方式——JNA。当然,如果用C调用Java,那就只能用JNI了。JNI使用复杂,尤其是提供的函数使用时一定要注意内存问题。因为Java层申请内存后是没有内存释放的,完全依赖java虚拟机来释放,而C层不然,必须时刻谨记申请的内存一定要及时释放。

JNI函数大全可参考:https://www.cnblogs.com/H-BolinBlog/p/6097829.html

 

JNI使用时会遇到诸多问题,目前我遇到的问题如下:

1、New作为前缀的方法,如NewByteArray()等,在使用完毕后,必须手动调用DeleteLocalRef()来释放(返回值除外)。
GetByteArrayELement()必须要调用ReleaseByteArrayElements()进行释放。如果只是想取jbytearray中的数据,那么完全可以用GetByteArrayRegion()实现。
2、在不同线程调用java方法,需要保存jobject对象,这时需要将jobject对象用NewGlobalRef()函数将其转化为全局引用,使用完毕后使用DeleteLocalRef ()释放。
3、在JNI层获取到的jbytearray长度是整个byte数组的容量,而非有效数据长度。最好将数据格式化,如定义成LV格式,前若干字节作为长度标识,长度之后才是有效数据。
4、不同线程使用JNIEnv*对象,需要AttachCurrentThread将env挂到当前线程,否则无法使用env。
5、javap命令是对java的class文件操作;javah命令需要在包名到上一层路径运行才行,否则无法生成.h文件。
6、尽量避免频繁调用JNI或者是使用JNI传输大量到数据。
7、由于JNI层引用申请个数有限制,如果忘记释放引用(全局或本地)而又不断申请新的引用时就会出现这样的错误:Reference Table overflow (max=1024) 或者是 Reference Table overflow (max=512)。

 

最后,奉上我当时写的代码,java类的功能是HTTPS收发,用来给Native层使用。

java类如下:


public class JniCallBack {

    private static JniCallBack jniCallBack;

    static {
        System.loadLibrary("java_fun");
    }

    public static JniCallBack getInstance(){
        if(jniCallBack == null){
            jniCallBack = new JniCallBack();
        }
        return jniCallBack;
    }

    private JniCallBack() {
    }

    public native void JNINativeInit();

    public static byte[] m_request  = new byte[2048];
    public static byte[] m_response = new byte[2048];
    public static byte[] m_url      = new byte[256];
    public static int    m_reqLen   = 0;
    public static int    m_respLen  = 0;
    public static int    m_urlLen   = 0;

    public static int sendRecv(){
        try {
            m_respLen = 0;

            SSLContext sslContext = SSLContext.getInstance("TLS");
            TrustManager[] tm = {new MyX509TrustManager()};
            sslContext.init(null, tm, new SecureRandom());

            byte[] bytesURL = new byte[m_urlLen];
            System.arraycopy(m_url, 0, bytesURL, 0, m_urlLen);
            String strUrl = new String(bytesURL);
            URL url = new URL(strUrl);

            //创建HttpURLConnection 对象
            HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
            conn.setSSLSocketFactory(sslContext.getSocketFactory());

            conn.setHostnameVerifier(new HostnameVerifier() {
                @Override
                public boolean verify(String arg0, SSLSession arg1) {
                    return true;
                }
            });
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(3000);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "x-ISO-TPDU/x-auth");
            conn.setRequestProperty("Connection", "Keep-Alive"); //请求的数据
            conn.setRequestProperty("User-Agent", "Donjin Http 0.1"); //请求的数据
            conn.setRequestProperty("Cache-Control", "no-cache"); //请求的数据
            conn.setRequestProperty("Accept", "*/*"); //请求的数据
            conn.setRequestProperty("Content-Length" , m_reqLen + ""); //设置输入和输出流
            conn.setDoOutput(true);
            conn.setDoInput(true);
            OutputStream os = conn.getOutputStream();
            os.write(m_request, 0, m_reqLen);
            os.flush();
            os.close(); //得到HTTP响应码


            InputStream is = conn.getInputStream(); //获取返回报文
            ByteArrayOutputStream output = new ByteArrayOutputStream();

            int n = 0, off = 0;
            while (-1 != (n = is.read(m_response))) {
                output.write(m_response, off, n);
                off += n;
            }

            m_respLen = conn.getContentLength();

            return m_respLen;
        }catch (Exception e){
            Log.e("",e.getMessage());
            e.printStackTrace();
        }
        return -1;
    }

}

JNI层java_fun.cpp文件如下:

#include "java_fun.h"
#include "string.h"


static JavaVM * g_javavm = NULL;

jbyteArray g_jba_req;
jbyteArray g_jba_resp;


int HttpExchange(unsigned char *response, int *pRespLen,
                 const unsigned char *request, int reqLen,
                 int timeout)
{

    int status;
    JNIEnv* _jniEnv = NULL;
    status = g_javavm->GetEnv((void **)&_jniEnv, JNI_VERSION_1_6);

    if (status < 0)
    {
        status = g_javavm->AttachCurrentThread(&_jniEnv, NULL);
        if (status < 0)
        {
            _jniEnv = NULL;
        }
    }

    if (NULL == _jniEnv)
    {
        return -1;
    }

    jclass tmpclass =_jniEnv->FindClass("com/bsit/qm702/jni/JniCallBack");

    _jniEnv->SetByteArrayRegion(g_jba_req, 0, reqLen, (jbyte*)request);
    _jniEnv->SetStaticIntField(tmpclass, _jniEnv->GetStaticFieldID(tmpclass, "m_reqLen", "I"), (jint)reqLen);

    int ret  = (int)_jniEnv->CallStaticIntMethod(tmpclass, _jniEnv->GetStaticMethodID(tmpclass, "sendRecv", "()I"));

    if (ret > 0)
    {
        _jniEnv->GetByteArrayRegion(g_jba_resp, 0, ret, (jbyte *)response);
        *pRespLen = ret;
    }

    //释放
    _jniEnv->DeleteLocalRef(tmpclass);

    return ret;
}




int HttpSetUrl(unsigned char *url, int urlLen)
{
    int status;
    JNIEnv* _jniEnv = NULL;
    status = g_javavm->GetEnv((void **)&_jniEnv, JNI_VERSION_1_6);

    if (status < 0)
    {
        status = g_javavm->AttachCurrentThread(&_jniEnv, NULL);
        if(status < 0)
        {
            _jniEnv = NULL;
        }
    }

    if (NULL == _jniEnv)
    {
        return -1;
    }

    jclass tmpclass =_jniEnv->FindClass("com/bsit/qm702/jni/JniCallBack");

    jbyteArray jba_url = (jbyteArray)_jniEnv->GetStaticObjectField(tmpclass, _jniEnv->GetStaticFieldID(tmpclass, "m_url", "[B"));

    _jniEnv->SetByteArrayRegion(jba_url, 0, urlLen, (jbyte*)url);
    _jniEnv->SetStaticIntField(tmpclass, _jniEnv->GetStaticFieldID(tmpclass, "m_urlLen", "I"), (jint)urlLen);

    //释放
    _jniEnv->DeleteLocalRef(tmpclass);
    _jniEnv->DeleteLocalRef(jba_url);

    return 0;
}



extern "C" JNIEXPORT void
JNICALL
Java_com_bsit_qm702_jni_JniCallBack_JNINativeInit(
        JNIEnv *env,
        jobject thiz) {

    env->GetJavaVM(&g_javavm);

    jclass tmpclass =env->FindClass("com/bsit/qm702/jni/JniCallBack");

    jobject tmpobj = env->NewObject(tmpclass, env->GetMethodID(tmpclass, "<init>", "()V"));


    jbyteArray jba_req  = (jbyteArray)env->GetStaticObjectField(tmpclass, env->GetStaticFieldID(tmpclass, "m_request", "[B"));
    g_jba_req  = (jbyteArray)env->NewGlobalRef(jba_req);

    jbyteArray jba_resp = (jbyteArray)env->GetStaticObjectField(tmpclass, env->GetStaticFieldID(tmpclass, "m_response", "[B"));
    g_jba_resp = (jbyteArray)env->NewGlobalRef(jba_resp);

    env->DeleteLocalRef(jba_req);
    env->DeleteLocalRef(jba_resp);
    env->DeleteLocalRef(tmpclass);
    env->DeleteLocalRef(tmpobj);

}

extern "C" JNIEXPORT void
JNICALL
Java_com_bsit_qm702_jni_JniCallBack_JNINativeFinal(
        JNIEnv *env,
        jobject thiz) {

    env->DeleteGlobalRef(g_jba_req);
    env->DeleteGlobalRef(g_jba_resp);
}

 

 

LLVM 编译器学习笔记之三十六-- 指令调度Instruction scheduling 1、参考Instruction scheduling in LLVM - 知乎,在中后端均存在指令调度 指令调度模型 2、在llvm12->llvm14 中Machine Instruction Scheduler有个patch增强了load/store指令的合并,也就是指令调度不仅仅只是改变指令的顺序,该优化类似gcc中的store-merge优化 ..................................................................... 阅读详情

相关推荐

麒麟V10 x86_64系统下Qt 5.12.7安装全攻略(附常见报错解决方案)

本文详细介绍了在麒麟V10 x86_64系统上安装Qt 5.12.7的完整流程,包括在线和离线两种安装方案,并提供了常见报错的解决方案。从环境准备到项目配置优化,再到高级调试技巧,全面覆盖Qt开发在国产操作系统上的实践要点,帮助开发者高效搭建开发环境。

weixin_29294395的博客 508

破解Android P对非SDK接口限制

众所周知,Android P 引入了针对非 SDK 接口(俗称为隐藏API)的使用限制。这是继 Android N上针对 NDK 中私有库的链接限制之后的又一次重大调整。从今以后,不论是native层的NDK还是 Java层的SDK,我们只能使用Google提供的、公开的标准接口。这对开发者以及用户乃至整个Android生态,当然是一件好事。但这也同时意味着Android上的各种黑科技有可能会逐渐...

yun_simon的博客 2898

vesta软件_分子动力学计算实战:利用 OVITO 软件找弗伦克尔缺陷和位错环分析

今天继续和大家分享这篇纯分子动力学(MD)的 Nat. Comm. 文章(DOI:10.1038/s41467-018-07102-3)。上期推文(从一篇 Nat. Comm. 学习经典分子动力学基本知识和相关软件基本操作 (一)),我们借用该文章的 fig.1 简单介绍了如何用文中所提到的 LAMMPS 软件来实现材料中级联碰撞过程。但是,想完整的展示类似该文章的 fig.1,单纯利用...

weixin_39524842的博客 5982

Android NDK 开发中正确释放 JNI 对象

如果在 C++ 创建子线程,通过 AttachCurrentThread 获取到 JNIEnv,调用 FindClass 是会报错的,通常而言,如果需要 FindClass ,尽量在 JNI_OnLoad 去创建一个全局的变量。而 GetStringRegion 和 GetByteArrayRegion 是我们自己分配好内存,然后把指针传给jni,jni往指针写入数据,所以不需要jni去释放内存,但是我们自己分配的空间不需要使用后必须释放。错误❌:不能在 Release 之后使用,会导致野指针。

zhangmiaoping23的专栏 1540

本地部署开源视频会议解决方案 Jitsi Meet 并实现外网访问

Jitsi Meet 是一款基于 WebRTC 技术的开源视频会议解决方案,它允许用户通过互联网进行高质量的视频通话、语音通话和文本聊天,非常适合用于在线教育、远程办公、团队协作等场景。本文将详细介绍如何利用 Docker 在本地部署 Jitsi Meet 并结合路由侠实现外网访问本地部署的 Jitsi Meet。

lyxnwct的博客 1945

鸿蒙OS开机动画背后的秘密:从代码到视觉的完整解析(附源码分析)

本文深入解析了鸿蒙OS开机动画的系统级实现原理。从bootanimation服务的启动配置、与Render Service的协同,到基于VSync信号的帧率同步与绘制流水线,结合OpenHarmony源码进行了逐行解读。文章揭示了其事件驱动的优雅退出机制,并探讨了视频支持、多屏适配等高级特性与定制化可能,为开发者理解鸿蒙图形子系统提供了硬核技术视角。

sony5的博客 971

linux中byte数组长度,android – JNI:如何获得jbyteArray大小

背景我正在使用JNI中的字节数组.而且我无法获得jbyteArray的长度.我正在Windows 7中的eclipse中编写代码.private native int Enroll( byte[] pSeed );JNI代码:在JNI中,我有一个结构,它有两个成员无符号长度和无符号字符数据[1]typedef struct blobData_s {unsigned long length;...

weixin_35648203的博客 853

大模型蒸馏实战:让小模型获得大模型的知识

本文为初学者提供了一份大模型蒸馏实战指南,通过情感分析任务演示如何将 BERT 的知识迁移到轻量级 TextCNN。文章结合原理图解与 PyTorch 代码,详解软标签生成、温度调节和双损失设计等核心概念,并对比蒸馏前后的性能差异(准确率提升 4.6%,推理速度达 1200 句 / 秒)。内含可直接运行的代码片段、训练技巧及常见问题解答,助力开发者快速掌握模型压缩核心技术,实现工业级部署效率。适合 NLP 入门者学习实践。

1368

jni调用java private,MonoDroid的JNI的Java反射来调用一个私有方法

In a Monodroid project, I need to be able to call a private method on a class. From an answer on a related question, it seems that this is possible in Java via reflection:import java.lang.reflect.Inv...

weixin_33748493的博客 469

SO_KEEPALIVE、TCP_KEEPIDLE、TCP_KEEPINTVL、保活包

是一个套接字选项,用于设置是否启用 keepalive 机制。在这段代码中没有涉及到选项的设置。当被设置为非零值时,表示启用 keepalive 机制。keepalive 是一种用于检测连接是否仍然有效的机制。通过定期发送一些特定的探测数据,可以检测到网络连接的异常中断或对端应用程序的崩溃退出。为了避免以上情况,可以启用 keepalive 机制,即使在无数据传输的情况下也定期发送探测数据。如果在一定时间内没有收到对端的响应,就认为连接已经失效,并进行相应的处理。要启用选项,需要使用函数。其中,fd。

m0_46376834的博客 4816

【前沿】多模态数据时间同步与对齐技术方案

多模态系统时间同步面临硬件差异、传输延迟和时钟漂移等核心挑战。解决方案包括硬件级的GPS授时(μs级)、FPGA同步电路,以及软件级的动态时间规整(DTW)、卡尔曼滤波和Transformer跨模态对齐算法。工程实践中采用滑动窗口缓冲、分布式一致性协议等方法,已在工业质检(误差≤0.1mm)、自动驾驶(延迟<30ms)等场景取得显著效果。未来需解决高动态场景鲁棒性、边缘设备能耗优化等问题,随着TSN和5G URLLC技术的发展,微秒级同步将成为可能。

从技术实践立足,从项目管理方法论延伸思考 1393

JNI编程注意事项

整理项目文档时, 忽然发现当年的一篇以前公司里关于JNI编程 的标准化文档。做为收藏,就贴在这里吧。 注:关于JNI, 现在好像有一个OpenSource项目jace可以帮助进行JNI的开发。另外, 推荐IBM Developerworks网站上的一个教程《用jni进行java编程》 JNI编程注意事项: 1、  JNI的函数声明: JNI函数声明方法为JAVA_Pac

进击吧!! 676

uniapp(安卓苹果APP端):解决video组件播放视频卡顿,视频一直加载非常缓慢或加载不出来解决方案,解决多个video组件视频播放很卡一直加载非常慢怎么办(无论真机调试还是本地测试都完美搞定)

uni-app APP端video组件播放视频卡顿,uniapp video app 加载不出来解决方案,uniapp app使用video视频播放卡顿,uni-app APP端video组件播放视频卡顿_uniapp video老是加载,uniapp开发app视频在真机上卡顿,安卓app播放视频很卡,苹果ios真机运行播放视频加载很慢怎么办,解决UniApp中MP4视频播放卡顿问题,解决m3u8视频播放很卡的问题,uniapp 使用video组件,部分视频加载非常慢,uniapp视频播放卡顿,安卓视频播放

✅ 精选推荐文章 7915

JNI注意事项

1. 在 java类中 声明 native函数 时,必须 包含 所有的 native函数,不然 会报 找不到 method的 错误 。 2. 在 JNI中 会回调 java中的 函数 ,函数 声明 必须一致。     method_API1 = env->GetMethodID(jniCallbackClass, "API1", "(I)V");     method_API2 = env-

705

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

关于 调用 JNI JAR java 的说明和注意事项,调用第 靠写不下了

关于 调用 JNI JAR java 的说明和注意事项,调用第 靠写不下了

weixin_34405557的博客 126

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java之JNI编程注意事项

整理项目文档时, 忽然发现当年的一篇以前公司里关于JNI编程 的标准化文档。做为收藏,就贴在这里吧。 注:关于JNI, 现在好像有一个OpenSource项目jace可以帮助进行JNI的开发。另外, 推荐IBM Developerworks网站上的一个教程《用jni进行java编程》 JNI编程注意事项: 1、  JNI的函数声明: JNI函数声明方法为JAVA_Pac

405

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

关于使用JNI的注意事项

原文来自于官方安卓开发文档中使用JNI相关注意事项,但同样也适用于其他情况下的JNI相关开发: 其中比较重要的是JNI与线程,以下是我对这一部分的翻译: JNI之线程篇 所有的线程都是由Linux内核进行规划的Linux线程(注:因为这篇文章是出自安卓开发,所以这么说). 它们通常都是产生于Managed code(关于什么是Managed code:https://en.wikipedia.org/wiki/Managed_code),比如类似于Thread.start()这样的Managed.

GoGoMonkey的博客 328

JNI调用的注意事项

JNI的简单教程网上很多,看看就能够明白,照着操作也基本能够做下来。但是因为大多的教程写的都不够详细,所以在照着操作时候可能会遇到几个小问题,在这里简单总结一下。1.在C语言环境中编译代码,出现编译错误,类型为找不到jni.h文件。解决方法:在jdk中寻找到jni.h和jni_md.h文件,将这两个文件拷贝到C语言编译器的include目录中。具体的目录可能会跟编译器有关。比如Dev C++中

::: 移动互联网时代开发者 ::: 2746

JNI需要注意事项

1、 System.loadLibrary("xxx"); 注意库的命名规则是libxxx.so 2、加载库和本地方法尽量写成一个类:        public class RecordJNI {         public native int StartRecord(String path);         static{                     System.

Lin's Home 633

JNI开发注意事项

JNI开发注意事项1、包含native方法的java类写在src/main/java/包名目录下2、用javac HelloJni.java生成class文件,用javah -classpath E:\ASWorkspace\LoadImage\app\src\main\java  包名.HelloJni生成.h头文件3、在src/main目录下新建一个jni目录,将生成的HelloJni.h文件...

u010015933的博客 362
上一篇: Linux下使用Git上传和更新代码(GitHub或码云)
下一篇: ubuntu卸载安装的方式
力宁
博客等级 码龄12年 13粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值