JNI,C ++将字符串推入堆栈

Posted

技术标签:

【中文标题】JNI,C ++将字符串推入堆栈【英文标题】:JNI, C++ push string in stack 【发布时间】:2018-12-30 10:42:24 【问题描述】:

我的 C++ 代码,将字符串推送到 mystack

#include <iostream>
#include <stack>
#include "NativeLogger.h"


std::stack<std::string> mystack;


JNIEXPORT void JNICALL
Java_NativeLogger_push(JNIEnv *env, jobject obj,jstring name)


  std::string s = env->GetStringUTFChars(name, 0);

  mystack.push(s);

  return;


JNIEXPORT void JNICALL
Java_NativeLogger_pop(JNIEnv *env, jobject obj)


  mystack.pop();
  return;

我在使用 Java 运行时收到了以下崩溃报告,知道如何修复它吗?

Java 运行时环境检测到致命错误:

SIGSEGV (0xb) 在 pc=0x00007f29421a0207, pid=18007, tid=0x00007f2942d3e700

JRE 版本:Java(TM) SE 运行时环境 (8.0_144-b01) (build 1.8.0_144-b01) Java VM:Java HotSpot(TM) 64 位服务器 VM(25.144-b01 混合模式 linux-amd64 压缩 oops)有问题的框架:C [libc.so.6+0x97207] __libc_malloc+0x197

【问题讨论】:

【参考方案1】:

Java 代码:

package recipeNo025;

public class HelloWorld 

  public static native void pushString(String s);
  public static native String popString();

  static 
    System.loadLibrary("HelloWorld");
  

  public static void main(String[] args) 
    HelloWorld.pushString("Hello");
    System.out.println(HelloWorld.popString());
  

C++ 代码

#include <iostream>
#include <stack>
#include "jni.h"
#include "recipeNo025_HelloWorld.h"

std::stack<std::string> mystack;

JNIEXPORT void JNICALL Java_recipeNo025_HelloWorld_pushString
  (JNIEnv *env, jclass obj, jstring str) 

    // we have to get string bytes into C string
    const char *c_str;
    c_str = env->GetStringUTFChars(str, NULL);
    if(c_str == NULL) 
        return;
    

    std::cout << "Passed string: " << c_str << std::endl;

    std::string my_string(c_str);
    mystack.push(my_string);

    // after using it, remember to release the memory
    env->ReleaseStringUTFChars(str, c_str);


JNIEXPORT jstring JNICALL Java_recipeNo025_HelloWorld_popString
  (JNIEnv *env, jclass obj) 

    std::string s = mystack.top();
    mystack.pop();
    return env->NewStringUTF(s.c_str());

执行:

> java -Djava.library.path=:./lib -cp target recipeNo025.HelloWorld
Passed string: Hello
Hello

另外,我会考虑使用单例模式,而不是使用堆栈的全局变量。

【讨论】:

您好 mko,感谢您的回答。您的代码适用于一个简单的示例。我检测了从堆栈中推送和弹出的整个 JDK 和日志方法。我仍然收到错误消息。 有时,调试 JNI 可能会很痛苦。在此处查看有关调试代码的提示:youtu.be/8Cjeq4l5COU 再次感谢,我发现是并发问题,使用 mutex.lock()/unlock() 解决了这个问题。 .oOo。凉爽的!玩 JNI ;) .oOo.【参考方案2】:

GetStringUTFChars 很可能返回了一个指向实际字符串的副本的指针,您立即将其作为参数传递给std::string 的构造函数,从而立即将其丢弃,从而导致内存泄漏。

您需要抓住指针才能释放它:

const char *p = env->GetStringUTFChars(name, NULL);
std::string s(p);
env->ReleaseStringUTFChars(name, p);

请注意,即使在不太可能的情况下没有复制,您仍然需要调用 ReleaseStringUTFChars,因为 VM 可能已将 Java 字符串固定在内存中,这可能会干扰垃圾收集器。

【讨论】:

以上是关于JNI,C ++将字符串推入堆栈的主要内容,如果未能解决你的问题,请参考以下文章

将 xmm 寄存器推入堆栈时出错

推送到包含C中唯一唯一值的堆栈

将堆栈用于局部变量的想法是啥?

C 编程:前向变量参数列表

如何将字符推入字符串堆栈?

将参数从 C/C++ JNI 传递到 Java 并获取修改后的值