你真的瞭解 NDK 和 jni 的區別嗎

codeGoogle發表於2017-08-08

首先我們要知道Java是如何呼叫c/c++的

Markdown
Markdown

什麼是JNI

java native interface(java本地介面)
ABI: application binary interface (應用程式二進位制介面)

簡介

JNI是Java語言提供的Java和C/C++相互溝通的機制,Java可以通過JNI呼叫本地的C/C++程式碼,本地的C/C++的程式碼也可以呼叫java程式碼。JNI 是本地程式設計介面,Java和C/C++互相通過的介面。Java通過C/C++使用本地的程式碼的一個關鍵性原因在於C/C++程式碼的高效性。

NDK是一系列工具的集合。它提供了一系列的工具,幫助開發者快速開發C(或C++)的動態庫,並能自動將so和java應用一起打包成apk。這些工具對開發者的幫助是巨大的。它整合了交叉編譯器,並提供了相應的mk檔案隔離CPU、平臺、ABI等差異,開發人員只需要簡單修改mk檔案(指出“哪些檔案需要編譯”、“編譯特性要求”等),就可以建立出so。它可以自動地將so和Java應用一起打包,極大地減輕了開發人員的打包工作。

#為什麼要使用JNI

  • 複用很多優秀的c/c++程式碼
    • ffmpeg 多媒體播放器
    • opencv 圖形識別引擎
    • 7-zip 壓縮
    • opencore 視訊播放
  • 效率問題
    • java程式碼跨平臺,不直接操作硬體,虛擬機器解釋執行。垃圾回收機制。
    • art 在安裝apk應用程式的時候,把apk裡面的dex翻譯成機器碼(apk的體積會變大)
    • c程式碼直接操作硬體,程式設計師可以手工的釋放記憶體
  • 應用場景問題
    • c程式碼可以直接操作硬體。
    • java程式碼只能操作虛擬機器(一次編譯到處執行)
    • 智慧家居操作硬體
    • 車載電腦(obd: onboard debug system)
  • 特殊業務邏輯
    • c程式碼反編譯困難,除錯困難。
    • java程式碼反編譯容易,很容易看懂。

#怎麼使用JNI

  • 看懂c程式碼( 有c語言基礎)
  • 懂流程 (熟悉jni的規範)
  • 熟練(NDK 工具 native develop kits)

開發工具

dev-cpp.exe

  1. 輕量級開發工具
  2. 編譯器gcc c99標準

Java通過JNI機制和C/C++溝通的具體步驟

  • 1、編寫包含native本地方法的java類
  • 2、通過javah工具生成C/C++語言的標頭檔案
  • 3、使用C/C++語言實現標頭檔案
  • 4、使用交叉編譯工具對C/C++原生程式碼進行編譯
  • 5、最後通過連結生成*.so可執行的C/C++庫

實際執行Java程式碼去和本地的C/C++程式碼互相溝通

JNI中的JavaVM與JNIEnv物件

在標準的Java平臺下,每個Process裡可以產生很多JavaVM物件,每個JavaVM物件都有一個與之對應的JavaVM物件,但是在Android平臺上,每個Process只能產生一個DalvikVM物件,也就是說在一個Android的程式中是通過有且只有一個虛擬器物件來服務所有Java和C++程式碼的。

  • 1、JNIEnv 內部包含一個Pointer,Pointer指向Dalvik的JavaVM物件的Fanction Table,JNIEnv 關於程式執行環境的眾多函式正是來源於Dalvik虛擬機器
  • 2、Android中每當一個Java執行緒第一次要呼叫本地C/C++程式碼時,Dalvik虛擬機器例項會為該Java執行緒產生一個JNIEnv *指標
  • 3、Java每條執行緒在和C/C++互相呼叫時,JNIEnv是相互獨立的,互不干擾
    4、每本地的C/C++程式碼想獲得當前執行緒所要使用的JNIEnv時,可以使用Dalvik VM物件的Java VM
    jvm->getEnv()方法,該方法即會返回當前執行緒所在的JNIEnv*
Java、Dalvik VM、C/C++的執行機制與流程 在Android的NDK中,Java、C/C++、Dalvik VM關係如下:
  • 1、java的dex位元組碼和C/C++的*.so同時執行DalvikVM之內,共同使用一個程式空間。每次使用jni呼叫c/c++開闢一個執行緒去處理
  • 2、java和C/C++可以相互呼叫,呼叫的關鍵是DalvikVM
  • 3、一般而言,比較經典的模式是Java通過JNI的C組建和C++相互溝通,一般業務處理放在C/C++中
  • 4、C++程式碼處於核心控制地位更具價值

當java需要C/C++程式碼時,在DalvikVM虛擬機器中載入動態連結庫時,會先呼叫JNI_Onload()函式,此時就會把javaVM物件的指標儲存於C層JNI組建的全域性環境中,在JAVA層呼叫C層的本地庫函式時,呼叫C本地函式執行緒必然通過Dalvik VM來呼叫C本地函式,測試Dalvik虛擬機器會為本地的C組建例項化一個JNIEnv指標,該指標指向Dalvik虛擬機器的具體函式列表,當JNI的C元件呼叫java層方法和屬性時,需要通過JNIEnv指標來進行呼叫。

當C++元件主動呼叫Java層方法時,需要通過JNI的C元件把JNIEnv指標傳遞給C++元件,此後,c++元件即可通過JNIEnv指標來掌控Java層程式碼。

NDK和jni的區別

對於JNI和NDK很多Android開發初學者沒有搞明白這個問題:

  • JNI是Java呼叫Native機制,是Java語言自己的特性全稱為Java Native Interface
  • 類似的還有微軟.Net Framework上的p/invoke,可以讓C#或Visual Basic.NET可以呼叫C/C++的API,所以說JNI和Android沒有關係
  • 在PC上開發Java的應用,如果執行在Windows平臺使用JNI是是經常的,比如說讀寫Windows的登錄檔。- 而NDK是Google公司推出的幫助Android開發者通過C/C++本地語言編寫應用的開發包,包含了C/C++的標頭檔案、庫檔案、說明文件和示例程式碼
  • 我們可以理解為Windows Platform SDK一樣,是純C/C++編寫的,但是Android並不支援純C/C++編寫的應用
  • 同時NDK提供的庫和函式功能很有限,僅僅處理些演算法效率敏感的問題

    Markdown
    Markdown

相信自己,沒有做不到的,只有想不到的

如果你覺得此文對您有所幫助,歡迎入群 QQ交流群 :232203809
微信公眾號:終端研發部

技術+職場
技術+職場

相關文章