【问题标题】:JNI, C++ push string in stackJNI,C ++将字符串推入堆栈
【发布时间】: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

【问题讨论】:

    标签: java c++ java-native-interface


    【解决方案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 字符串固定在内存中,这可能会干扰垃圾收集器。

    【讨论】:

      猜你喜欢
      • 2011-04-22
      • 2021-12-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多