歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C/C++啟動Java虛擬機

Android系統基於Linux,它在用戶空間的第一個進程是init進程,是屬於native性質的進程,但是每個android應用都是跑在虛擬機下邊的,第一個虛擬機進程zygote就是被init進程給fork出來的,這就涉及到了如何用native的c/c++代碼啟動jvm,本文就是做一個小示例來演示一下。

新建一個目錄,添加main.cpp,代碼如下:

#include<iostream>
#include<jni.h>
#include<cstdlib>

using namespace std;

int main(){
 JavaVM* mJavaVM;
 JNIEnv* env;
 const int size = 3;
 JavaVMOption options[size];
 options[0].optionString = "-Djava.compiler=NONE";
 options[1].optionString = "-Djava.class.path=./"; //指定當前目錄為classpath路徑

 options[2].optionString=  "-verbose:class";         

 JavaVMInitArgs initArgs;
 initArgs.version = JNI_VERSION_1_4;
 initArgs.options = options;
 initArgs.nOptions = size;
 initArgs.ignoreUnrecognized = JNI_TRUE;

 if (JNI_CreateJavaVM(&mJavaVM, (void **)&env, &initArgs) != 0) {
  cout<<"創建JVM失敗!"<<endl;
 }else{
  cout<<"創建JVM成功!"<<endl;
  jclass startClass =env->FindClass("com/hello/HelloWorld");
  jmethodID startMeth;
  if(startClass){
   cout<<"成功找到類!"<<endl;
   startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
   env->CallStaticVoidMethod(startClass, startMeth, NULL);
  }else{
   cout<<"找不到指定的類!"<<endl;
  }
 
 } 
 return 0;
}

啟動jvm需要使用jni中的函數jint JNI_CreateJavaVM(JavaVM **p_vm, JNIEnv **p_env, void *vm_args);

第一個和第二個參數都是輸入參數,放到函數中被初始化的。第三個參數應傳遞JavaVMInitArgs結構體的指針,JavaVMInitArgs的定義如下:

typedef struct JavaVMInitArgs {
    jint version;

    jint nOptions;
    JavaVMOption *options;
    jboolean ignoreUnrecognized;
} JavaVMInitArgs;

1.version代表jni的版本,我這裡填寫的是JNI_VERSION_1_4

2.nOptions代表下邊的JavaVMOption數組的個數

3.options代表JavaVMOption 數組類型,JavaVMOption的定義為:

typedef struct JavaVMOption {
    char *optionString;  /* the option as a string in the default platform encoding */
    void *extraInfo;
} JavaVMOption;

4.ignoreUnrecognized值為JNI_FALSE或者JNI_TRUE,如果是JNI_TRUE,那麼JNI_CreateJavaVM函數會忽略掉所有無效選項以"-X"或"_"開頭的。如果是JNI_FALSE,那麼JNI_CreateJavaVM函數遇到無效選項時會返回一個JNI_ERR.

編譯main.cpp:main.cpp包含了jni.h,後者又包含了jni_md.h,這兩個文件的路徑分別如下:/usr/lib/jvm/java-6-sun-1.6.0.26/include

/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux

要使用JNI_CreateJavaVM函數,需要鏈接libjvm.so動態庫,路徑如下:

/usr/lib/jvm/java-1.5.0-sun-1.5.0.15/jre/lib/i386/server

因此編譯方法如下:

$ g++ -I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux -L/usr/lib/jvm/java-1.5.0-sun-1.5.0.15/jre/lib/i386/server/ -ljvm main.cpp

在同級目錄創建一個java文件HelloWorld.java:

package com.hello;
public class HelloWorld{

 public static void main(String[] args){
  System.out.println("Hello world from java!");
 }
}

編譯此文件:$ javac -d . HelloWorld.java

接下來要運行a.out還需一個步驟:修改當前終端的動態鏈接庫環境變量讓它能找到libjvm.so.$ export LD_LIBRARY_PATH=/usr/lib/jvm/java-1.5.0-sun-1.5.0.15/jre/lib/i386/server:$LD_LIBRARY_PATH

然後運行 ./a.out會出現輸出:創建jvm成功!成功找到類!

Hello world from java!

-------------------啟動了java虛擬機以後,如果使用ps命令查看運行的進程,就會發現java虛擬機仍然運行在a.out可執行文件被加載起來的進程中,而且只有java虛擬機退出了,才會繼續執行main.cpp剩余的代碼。

Copyright © Linux教程網 All Rights Reserved