JNI使用的是改良的UTF-8格式的Strings。
以下文檔來自官方:
Modified UTF-8 Strings
The JNI uses modified UTF-8 strings to represent various string types. Modified UTF-8 strings are the same as those used by the Java VM. Modified UTF-8 strings are encoded so that character sequences that contain only non-null ASCII characters can be represented using only one byte per character, but all Unicode characters can be represented.
翻譯:
JNI使用的是改良的UTF-8格式的Strings來表示各種字符串類型。改良的UTF-8的strings和Java VM使用的是一樣的。改良的UTF-8的strings編碼,使得僅包含非空ASCII字符的字符序列能夠按每字符占一個字節來表示,但所有的Unicode字符均可以被表示出來。
String Operations(String 操作)
1.NewString -- 創建String
jstring NewString(JNIEnv *env, const jchar *unicodeChars,jsize len);
Constructs a new java.lang.String object from an array of Unicode characters.
通過Unicode字符的數組來創建一個新的String對象。備注:Unicode和UTF-8還是有區別的。
參數:
env:JNI 接口指針。
unicodeChars:指向 Unicode 字符串的指針。
len:Unicode 字符串的長度。
返回值:
Java 字符串對象。如果無法構造該字符串,則為 NULL。
拋出:
OutOfMemoryError:如果系統內存不足。
2.GetStringLength -- 獲取String的長度
jsize GetStringLength(JNIEnv *env, jstring string);
Returns the length (the count of Unicode characters) of a Java string.
返回 Java 字符串的長度(Unicode 字符數)。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
返回值:
Java 字符串的長度。
3.GetStringChars -- 獲取StringChars的指針
const jchar * GetStringChars(JNIEnv *env, jstring string,jboolean *isCopy);
Returns a pointer to the array of Unicode characters of the string. This pointer is valid until ReleaseStringchars() is called.
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
返回指向字符串的 Unicode 字符數組的指針。該指針在調用 ReleaseStringchars() 前一直有效。
如果 isCopy 非空,則在復制完成后將 *isCopy 設為 JNI_TRUE。如果沒有復制,則設為JNI_FALSE。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
isCopy:指向布爾值的指針。
返回值:
指向 Unicode 字符串的指針,如果操作失敗,則返回NULL。
4.ReleaseStringChars -- 釋放StringChars
void ReleaseStringChars(JNIEnv *env, jstring string,const jchar *chars);
Informs the VM that the native code no longer needs access to chars. The chars argument is a pointer obtained from string using GetStringChars().
通知虛擬機平台相關代碼無需再訪問 chars。參數 chars 是一個指針,可通過 GetStringChars() 從 string 獲得。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
chars:指向 Unicode 字符串的指針。
UTF-8
5.NewStringUTF -- 創建UTF的String
jstring NewStringUTF(JNIEnv *env, const char *bytes);
Constructs a new java.lang.String object from an array of characters in modified UTF-8 encoding.
通過改良的 UTF-8 字符數組構造新 java.lang.String 對象。
參數:
env:JNI 接口指針。如果無法構造該字符串,則為 NULL。
bytes:指向 UTF-8 字符串的指針。
返回值:
Java 字符串對象。如果無法構造該字符串,則為 NULL。
拋出:
OutOfMemoryError:如果系統內存不足。
6.GetStringUTFLength -- 獲取UTF的String的長度
jsize GetStringUTFLength(JNIEnv *env, jstring string);
Returns the length in bytes of the modified UTF-8 representation of a string.
以字節為單位返回字符串的 UTF-8 長度。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
返回值:
返回字符串的 UTF-8 長度。
7.GetStringUTFChars -- 獲取StringUTFChars的指針
const char * GetStringUTFChars(JNIEnv *env, jstring string,jboolean *isCopy);
Returns a pointer to an array of bytes representing the string in modified UTF-8 encoding. This array is valid until it is released by ReleaseStringUTFChars().
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
返回指向字符串的 UTF-8 字符數組的指針。該數組在被ReleaseStringUTFChars() 釋放前將一直有效。
如果 isCopy 不是 NULL,*isCopy 在復制完成后即被設為 JNI_TRUE。如果未復制,則設為 JNI_FALSE。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
isCopy:指向布爾值的指針。
返回值:
指向 UTF-8 字符串的指針。如果操作失敗,則為 NULL。
8.ReleaseStringUTFChars -- 釋放StringUTFChars
void ReleaseStringUTFChars(JNIEnv *env, jstring string,const char *utf);
Informs the VM that the native code no longer needs access to utf. The utf argument is a pointer derived from string using GetStringUTFChars().
通知虛擬機平台相關代碼無需再訪問 utf。utf 參數是一個指針,可利用 GetStringUTFChars() 從 string 獲得。
參數:
env:JNI 接口指針。
string:Java 字符串對象。
utf:指向 UTF-8 字符串的指針。
Note
In JDK/JRE 1.1, programmers can get primitive array elements in a user-supplied buffer. As of JDK/JRE 1.2 additional set of functions are provided allowing native code to obtain characters in Unicode (UTF-16) or modified UTF-8 encoding in a user-supplied buffer. See the functions below.
注意:
在JDK/JRE 1.1,程序員可以在用戶提供的緩沖區獲取基本類型數組元素。從JDK/JRE1.2之后,提供了額外的方法,這些方法允許在用戶提供的緩沖區獲取Unicode字符(UTF-16編碼)或者是UTF-8的字符。這些方法詳見如下:
9.GetStringUTFRegion
void GetStringRegion(JNIEnv *env, jstring str, jsize start, jsize len, jchar *buf);
Copies len number of Unicode characters beginning at offset start to the given buffer buf.
Throws StringIndexOutOfBoundsException on index overflow.
在str(Unicode字符)從start位置開始截取len長度放置到buf中。
拋出StringIndexOutOfBoundsException異常。
10.GetStringUTFRegion
void GetStringUTFRegion(JNIEnv *env, jstring str, jsize start, jsize len, char *buf);
Translates len number of Unicode characters beginning at offset start into modified UTF-8 encoding and place the result in the given buffer buf.
Throws StringIndexOutOfBoundsException on index overflow.
將str(Unicode字符)從start位置開始截取len長度轉換為改良的UTF-8編碼並將結果放置到buf中。
拋出StringIndexOutOfBoundsException異常。
11.GetStringCritical / ReleaseStringCritical
const jchar * GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy);
void ReleaseStringCritical(JNIEnv *env, jstring string, const jchar *carray);
The semantics of these two functions are similar to the existing Get/ReleaseStringChars functions. If possible, the VM returns a pointer to string elements; otherwise, a copy is made. However, there are significant restrictions on how these functions can be used. In a code segment enclosed by Get/ReleaseStringCritical calls, the native code must not issue arbitrary JNI calls, or cause the current thread to block.
The restrictions on Get/ReleaseStringCritical are similar to those on Get/ReleasePrimitiveArrayCritical.
這兩個函數的語義是類似於現有的 Get/ReleaseStringChars 功能。如果可能的話,虛擬機返回一個指向字符串元素的指針;否則,將返回一個復制的副本。然而使用這些方法是有值得注意的限制的。In a code segment enclosed by Get/ReleaseStringCritical calls, the native code must not issue arbitrary JNI calls, or cause the current thread to block.
備注:
為了提高JVM返回字符串直接指針的可能性,JDK1.2中引入了一對新函數,Get/ReleaseStringCritical。表面上,它們和Get/ReleaseStringChars函數差不多,但實際上這兩個函數在使用有很大的限制。
使用這兩個函數時,你必須兩個函數中間的代碼是運行在"critical region"(臨界區)的,即,這兩個函數中間的本地代碼不能調用任何會讓線程阻塞或等待JVM中的其它線程的本地函數或JNI函數。
有了這些限制, JVM就可以在本地方法持有一個從GetStringCritical得到的字符串的直接指針時禁止GC。當GC被禁止時,任何線程如果觸發GC的話,都會被阻塞。而Get/ReleaseStringCritical這兩個函數中間的任何本地代碼都不可以執行會導致阻塞的調用或者為新對象在JVM中分配內存。否則,JVM有可能死鎖,想象一下這樣的場景中:
1、 只有當前線程觸發的GC完成阻塞並釋放GC時,由其它線程觸發的GC才可能由阻塞中釋放出來繼續運行。
2、 在這個過程中,當前線程會一直阻塞。因為任何阻塞性調用都需要獲取一個正被其它線程持有的鎖,而其它線程正等待GC。
Get/ReleaseStringCritical的交迭調用是安全的,這種情況下,它們的使用必須有嚴格的順序限制。而且,我們一定要記住檢查是否因為內存溢出而導致它的返回值是NULL。因為JVM在執行GetStringCritical這個函數時,仍有發生數據復制的可能性,尤其是當JVM內部存儲的數組不連續時,為了返回一個指向連續內存空間的指針,JVM必須復制所有數據。
總之,為了避免死鎖,在Get/ReleaseStringCritical之間不要調用任何JNI函數。Get/ReleaseStringCritical和 Get/ReleasePrimitiveArrayCritical這兩個函數是可以的。
參考資料:
http://blog.csdn.net/mu0206mu/article/details/7182010
http://blog.csdn.net/a345017062/article/details/8068917
