成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java JNI深度分析與實(shí)踐

開發(fā) 后端
Java JNI是Java Native Interface的縮寫,中文可譯為Java本地調(diào)用。Java Native Interface (JNI)標(biāo)準(zhǔn)成為java平臺(tái)的一部分,它允許Java代碼和其他語言寫的代碼進(jìn)行交互。本文向您詳細(xì)介紹Java JNI。

Java 環(huán)境和語言對(duì)于應(yīng)用程序開發(fā)來說是非常安全和高效的。但是,一些應(yīng)用程序卻需要執(zhí)行純 Java 程序無法完成的一些任務(wù),比如:

與舊有代碼集成,避免重新編寫。

實(shí)現(xiàn)可用類庫中所缺少的功能。舉例來說,在 Java 語言中實(shí)現(xiàn) ping 時(shí),您可能需要 Internet Control Message Protocol (ICMP) 功能,但基本類庫并未提供它。

***與使用 C/C++ 編寫的代碼集成,以充分發(fā)掘性能或其他與環(huán)境相關(guān)的系統(tǒng)特性。

解決需要非 Java 代碼的特殊情況。舉例來說,核心類庫的實(shí)現(xiàn)可能需要跨包調(diào)用或者需要繞過其他 Java 安全性檢查。

JNI 允許您完成這些任務(wù)。它明確分開了 Java 代碼與本機(jī)代碼(C/C++)的執(zhí)行,定義了一個(gè)清晰的 API 在這兩者之間進(jìn)行通信。從很大程度上說,它避免了本機(jī)代碼對(duì) JVM 的直接內(nèi)存引用,從而確保本機(jī)代碼只需編寫一次,并且可以跨不同的 JVM 實(shí)現(xiàn)或版本運(yùn)行。

借助 JNI,本機(jī)代碼可以隨意與 Java 對(duì)象交互,獲取和設(shè)計(jì)字段值,以及調(diào)用方法,而不會(huì)像 Java 代碼中的相同功能那樣受到諸多限制。這種自由是一把雙刃劍:它犧牲 Java 代碼的安全性,換取了完成上述所列任務(wù)的能力。在您的應(yīng)用程序中使用 JNI 提供了強(qiáng)大的、對(duì)機(jī)器資源(內(nèi)存、I/O 等)的低級(jí)訪問,因此您不會(huì)像普通 Java 開發(fā)人員那樣受到安全網(wǎng)的保護(hù)。JNI 的靈活性和強(qiáng)大性帶來了一些編程實(shí)踐上的風(fēng)險(xiǎn),比如導(dǎo)致性能較差、出現(xiàn) bug 甚至程序崩潰。您必須格外留意應(yīng)用程序中的代碼,并使用良好的實(shí)踐來保障應(yīng)用程序的總體完整性。

本文介紹 JNI 用戶最常遇到的 10 大編碼和設(shè)計(jì)錯(cuò)誤。其目標(biāo)是幫助您認(rèn)識(shí)到并避免它們,以便您可以編寫安全、高效、性能出眾的 JNI 代碼。本文還將介紹一些用于在新代碼或已有代碼中查找這些問題的工具和技巧,并展示如何有效地應(yīng)用它們。

Java JNI 編程缺陷可以分為兩類

性能:代碼能執(zhí)行所設(shè)計(jì)的功能,但運(yùn)行緩慢或者以某種形式拖慢整個(gè)程序。

正確性:代碼有時(shí)能正常運(yùn)行,但不能可靠地提供所需的功能;最壞的情況是造成程序崩潰或掛起。

性能缺陷

程序員在使用 JNI 時(shí)的 5 大性能缺陷如下:

◆不緩存方法 ID、字段 ID 和類

◆觸發(fā)數(shù)組副本

◆回訪(Reaching back)而不是傳遞參數(shù)

◆錯(cuò)誤認(rèn)定本機(jī)代碼與 Java 代碼之間的界限

◆使用大量本地引用,而未通知 JVM

◆不緩存方法 ID、字段 ID 和類

要訪問 Java 對(duì)象的字段并調(diào)用它們的方法,本機(jī)代碼必須調(diào)用 FindClass()、GetFieldID()、GetMethodId() 和 GetStaticMethodID()。對(duì)于 GetFieldID()、GetMethodID() 和 GetStaticMethodID(),為特定類返回的 ID 不會(huì)在 JVM 進(jìn)程的生存期內(nèi)發(fā)生變化。但是,獲取字段或方法的調(diào)用有時(shí)會(huì)需要在 JVM 中完成大量工作,因?yàn)樽侄魏头椒赡苁菑某愔欣^承而來的,這會(huì)讓 JVM 向上遍歷類層次結(jié)構(gòu)來找到它們。由于 ID 對(duì)于特定類是相同的,因此您只需要查找一次,然后便可重復(fù)使用。同樣,查找類對(duì)象的開銷也很大,因此也應(yīng)該緩存它們。

舉例來說,清單 1 展示了調(diào)用靜態(tài)方法所需的 JNI 代碼:

清單 1. 使用 JNI 調(diào)用靜態(tài)方法

  1.    int val=1;   
  2.   jmethodID method;   
  3.   jclass cls;   
  4.   cls = (*env)->FindClass(env, "com/ibm/example/TestClass");   
  5.   if ((*env)->ExceptionCheck(env)) {   
  6.   return ERR_FIND_CLASS_FAILED;   
  7.   }   
  8.   method = (*env)->GetStaticMethodID(env, cls, "setInfo", "(I)V");   
  9.   if ((*env)->ExceptionCheck(env)) {   
  10.   return ERR_GET_STATIC_METHOD_FAILED;   
  11.   }   
  12.   (*env)->CallStaticVoidMethod(env, cls, method,val);   
  13.   if ((*env)->ExceptionCheck(env)) {   
  14.   return ERR_CALL_STATIC_METHOD_FAILED;   
  15.   } 

當(dāng)我們每次希望調(diào)用方法時(shí)查找類和方法 ID 都會(huì)產(chǎn)生六個(gè)本機(jī)調(diào)用,而不是***次緩存類和方法 ID 時(shí)需要的兩個(gè)調(diào)用。

緩存會(huì)對(duì)您應(yīng)用程序的運(yùn)行時(shí)造成顯著的影響。考慮下面兩個(gè)版本的方法,它們的作用是相同的。清單 2 使用了緩存的字段 ID:

清單 2. 使用緩存的字段 ID

  1.      int sumValues2(JNIEnv* env, jobject obj, jobject allValues){   
  2.   jint avalue = (*env)->GetIntField(env, allValues, a);   
  3.   jint bvalue = (*env)->GetIntField(env, allValues, b);   
  4.   jint cvalue = (*env)->GetIntField(env, allValues, c);   
  5.   jint dvalue = (*env)->GetIntField(env, allValues, d);   
  6.   jint evalue = (*env)->GetIntField(env, allValues, e);   
  7.   jint fvalue = (*env)->GetIntField(env, allValues, f);   
  8.   return avalue + bvalue + cvalue + dvalue + evalue + fvalue;   
  9.   } 

清單 3. 未緩存字段 ID

  1.    int sumValues2(JNIEnv* env, jobject obj, jobject allValues){   
  2.   jclass cls = (*env)->GetObjectClass(env,allValues);   
  3.   jfieldID a = (*env)->GetFieldID(env, cls, "a", "I");   
  4.   jfieldID b = (*env)->GetFieldID(env, cls, "b", "I");   
  5.   jfieldID c = (*env)->GetFieldID(env, cls, "c", "I");   
  6.   jfieldID d = (*env)->GetFieldID(env, cls, "d", "I");   
  7.   jfieldID e = (*env)->GetFieldID(env, cls, "e", "I");   
  8.   jfieldID f = (*env)->GetFieldID(env, cls, "f", "I");   
  9.   jint avalue = (*env)->GetIntField(env, allValues, a);   
  10.   jint bvalue = (*env)->GetIntField(env, allValues, b);   
  11.   jint cvalue = (*env)->GetIntField(env, allValues, c);   
  12.   jint dvalue = (*env)->GetIntField(env, allValues, d);   
  13.   jint evalue = (*env)->GetIntField(env, allValues, e);   
  14.   jint fvalue = (*env)->GetIntField(env, allValues, f);   
  15.   return avalue + bvalue + cvalue + dvalue + evalue + fvalue 

清單 2 用 3,572 ms 運(yùn)行了 10,000,000 次。清單 3 用了 86,217 ms — 多花了 24 倍的時(shí)間。

觸發(fā)數(shù)組副本

JNI 在 Java 代碼和本機(jī)代碼之間提供了一個(gè)干凈的接口。為了維持這種分離,數(shù)組將作為不透明的句柄傳遞,并且本機(jī)代碼必須回調(diào) JVM 以便使用 set 和 get 調(diào)用操作數(shù)組元素。Java 規(guī)范讓 JVM 實(shí)現(xiàn)決定讓這些調(diào)用提供對(duì)數(shù)組的直接訪問,還是返回一個(gè)數(shù)組副本。舉例來說,當(dāng)數(shù)組經(jīng)過優(yōu)化而不需要連續(xù)存儲(chǔ)時(shí),JVM 可以返回一個(gè)副本。(參見 參考資料 獲取關(guān)于 JVM 的信息)。

隨后,這些調(diào)用可以復(fù)制被操作的元素。舉例來說,如果您對(duì)含有 1,000 個(gè)元素的數(shù)組調(diào)用 GetLongArrayElements(),則會(huì)造成至少分配或復(fù)制 8,000 字節(jié)的數(shù)據(jù)(每個(gè) long 1,000 元素 * 8 字節(jié))。當(dāng)您隨后使用 ReleaseLongArrayElements() 更新數(shù)組的內(nèi)容時(shí),需要另外復(fù)制 8,000 字節(jié)的數(shù)據(jù)來更新數(shù)組。即使您使用較新的 GetPrimitiveArrayCritical(),規(guī)范仍然準(zhǔn)許 JVM 創(chuàng)建完整數(shù)組的副本。

GetTypeArrayRegion() 和 SetTypeArrayRegion() 方法允許您獲取和更新數(shù)組的一部分,而不是整個(gè)數(shù)組。通過使用這些方法訪問較大的數(shù)組,您可以確保只復(fù)制本機(jī)代碼將要實(shí)際使用的數(shù)組部分。

舉例來說,考慮相同方法的兩個(gè)版本,如清單 4 所示:

清單 4. 相同方法的兩個(gè)版本

  1.  jlong getElement(JNIEnv* env, jobject obj, jlongArray arr_j,   
  2.   int element){   
  3.   jboolean isCopy;   
  4.   jlong result;   
  5.   jlong* buffer_j = (*env)->GetLongArrayElements(env, arr_j, &isCopy);   
  6.   result = buffer_j[element];   
  7.   (*env)->ReleaseLongArrayElements(env, arr_j, buffer_j, 0);   
  8.   return result;   
  9.   }   
  10.   jlong getElement2(JNIEnv* env, jobject obj, jlongArray arr_j,   
  11.   int element){   
  12.   jlong result;   
  13.   (*env)->GetLongArrayRegion(env, arr_j, element,1, &result);   
  14.   return result;   
  15.   }   
  16.   } 

 

【編輯推薦】

  1. Java通過JNI調(diào)用C語言的方法
  2. Java: JNI完全手冊(cè)
  3. 探秘Java 7:JVM動(dòng)態(tài)語言支持詳解
  4. JScript、Java、JavaScript和JSP總結(jié)
  5. Java JDBC編程總結(jié)
責(zé)任編輯:佚名 來源: 網(wǎng)絡(luò)轉(zhuǎn)載
相關(guān)推薦

2011-06-16 08:43:39

JAVAJIN

2024-12-24 14:01:10

2025-03-27 04:10:00

2024-09-19 08:49:13

2024-08-30 09:53:17

Java 8編程集成

2023-12-04 16:18:30

2024-10-10 08:26:30

2009-07-24 13:54:39

MVVM模式

2018-03-14 08:10:44

深度學(xué)習(xí)

2023-05-08 12:03:14

Linux內(nèi)核進(jìn)程

2022-07-08 09:26:45

Flink快手計(jì)算

2024-07-08 07:30:47

2025-05-12 01:33:00

異步函數(shù)Promise

2009-09-03 11:47:43

Groovy與Java

2022-12-21 08:32:34

OLAPDruid架構(gòu)

2017-06-16 09:39:32

優(yōu)酷實(shí)踐阿里云

2011-03-01 09:23:47

移動(dòng)Web應(yīng)用開發(fā)成本

2025-03-25 10:29:52

2024-11-13 08:47:24

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 亚洲精品一二三区 | 国产精品观看 | 中文字幕一区二区三区精彩视频 | 美女福利视频 | 精品中文字幕在线观看 | 亚洲免费视频网站 | 看片wwwwwwwwwww | 黄色片在线网站 | 久久天堂网 | 国产美女永久免费无遮挡 | 美女视频一区二区 | 一级黄色录像毛片 | 91麻豆精品国产91久久久久久 | 久久久看 | 天天碰夜夜操 | 91久久| 国产精品成人一区 | 欧美精品91 | 成人欧美一区二区三区在线播放 | 特级一级黄色片 | 精品国产乱码久久久久久88av | 国产精品区二区三区日本 | 日韩视频一区二区在线 | 欧美综合久久 | 蜜桃色网 | 午夜精品视频在线观看 | 最新伦理片 | 在线一区二区三区 | 久久久91精品国产一区二区三区 | 澳门永久av免费网站 | 男人天堂网址 | 成人免费观看男女羞羞视频 | 综合激情av | 看片国产 | 国产一级在线观看 | av天空| 国产精品91网站 | 欧美国产日韩在线观看成人 | 久久爱黑人激情av摘花 | 激情五月婷婷 | 91亚洲国产成人久久精品网站 |