jni字符串处理传递的原理

java是unicode编码,本地层则是utf-8编码
java String转化时,必须先decode转化成mirror::String,然后再转化成utf-8编码

static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy)

作用:将java String转化为c语言中的const char*
本质:
     1. 将java String做decode操作 mirror::String* s = soa.Decode<mirror::String*>(java_string);
     2. 取出mirror::String中的内容。const uint16_t* chars = s->GetValue();  3. unicode转码为utf-8: ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
看来本地层是用一个mirror::String对象来描述一个decode后的字符串

char* bytes = new char[byte_count + 1];
可以看出本地层自己申请了一片内存,然后将字符串拷贝进来,返回这个字符串的const char*
很明显这个字符串占有的内存和java中对应的字符串占用的不是同一片内存。
natvie层只是将它拷贝到另一块内存区域,然后返回const char*。
void nativePrint(JNIEnv *env, jobject thiz, jstring jstr) {
    const char *nativeString = (*env)->GetStringUTFChars(env, jstr, 0);
    (*env)->ReleaseStringUTFChars(env, jstr, nativeString);
}

  
  static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
    if (java_string == nullptr) {
      return nullptr;
    }
    if (is_copy != nullptr) {
      *is_copy = JNI_TRUE;
    }
    ScopedObjectAccess soa(env);
    mirror::String* s = soa.Decode<mirror::String*>(java_string);
    size_t byte_count = s->GetUtfLength();
    char* bytes = new char[byte_count + 1];
    CHECK(bytes != nullptr);  // bionic aborts anyway.
    const uint16_t* chars = s->GetValue();
    ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
    bytes[byte_count] = '\0';
    return bytes;
  }
-------------------------------------------------------------------------------------------------------------
static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, char* buf)
GetStringUTFRegion和GetStringUTFChars类似,只是GetStringUTFRegion()在调用前需要先分配一块非const内存作为参数传进来。
而GetStringUTFChars()则是自己申请一块内存。调用完毕后返回的const char*,说明这块内存不让别人修改。

最后就是GetStringUTFRegion()copy到内存是局部变量,在栈上面,coder不用管理它。
GetStringUTFChars()调用完后copy到的内存是new出来的,虽然navie函数栈退出后,local ref table的内存是有限的,它会帮助释放这些内存。但是当我们不需要
使用这块内存时最好还是调用ReleaseStringUTFChars()去释放这块内存,以免local ref table内存不够用而溢出。
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj, jstring prompt)
{
    char outbuf[128];
    int len = (*env)->GetStringLength(env, prompt);
    (*env)->GetStringUTFRegion(env, prompt, 0, len, outbuf);
    printf("%s", outbuf);
}

  static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length, char* buf) {
    CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
    ScopedObjectAccess soa(env);
    mirror::String* s = soa.Decode<mirror::String*>(java_string);
    if (start < 0 || length < 0 || start + length > s->GetLength()) {
      ThrowSIOOBE(soa, start, length, s->GetLength());
    } else {
      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
      const jchar* chars = s->GetValue();
      ConvertUtf16ToModifiedUtf8(buf, chars + start, length);
    }
  }

 

posted @ 2016-03-02 16:04  牧 天  阅读(1740)  评论(0)    收藏  举报