为了解决这个问题,有一个比较好的方案是JNI,这个时候并不需要重新起一个Process,也就不会存在备份内存的问题,下面是一个例子.
1.编写java类JNIHelper.java
package com.pracbiz; public class JNIHelper { static { System.loadLibrary("JNI"); } public native String exec(String input); private static JNIHelper instance; private JNIHelper() { } public static JNIHelper getInstance() { synchronized(JNIHelper.class) { if(instance == null) { instance = new JNIHelper(); } } return instance; } public static void main(String[] args) { getInstance().exec("pwd"); } }
2.通过jdk自带的javah命令生成c头文件com_pracbiz_JNIHelper.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include/* Header for class com_pracbiz_JNIHelper */ #ifndef _Included_com_pracbiz_JNIHelper #define _Included_com_pracbiz_JNIHelper #ifdef __cplusplus extern "C" { #endif /* * Class: com_pracbiz_JNIHelper * Method: exec * Signature: (Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_pracbiz_JNIHelper_exec (JNIEnv *, jobject, jstring); #ifdef __cplusplus } #endif #endif
3.编写c++文件,实现头文件中的方法com_pracbiz_JNIHelper.cpp
#include "com_pracbiz_JNIHelper.h" #include#include #include #include #include #include using namespace std; JNIEXPORT jstring JNICALL Java_com_pracbiz_JNIHelper_exec (JNIEnv *env, jobject obj, jstring input) { std::string result; std::string cmd; FILE *fstream=NULL; char buff[1024]=""; char const *str = (char *)env->GetStringUTFChars(input, NULL); char const *ext = " 2>&1"; cmd.append(str); cmd.append(ext); memset(buff,0,sizeof(buff)); if(NULL==(fstream=popen(cmd.c_str(),"r"))) { fprintf(stderr,"execute command failed: %s",strerror(errno)); env->ReleaseStringUTFChars(input, str); return env->NewStringUTF("-1"); } env->ReleaseStringUTFChars(input, str); while (NULL!=fgets(buff, sizeof(buff), fstream)) { result.append(buff); } if (fstream != NULL) { pclose(fstream); } return env->NewStringUTF(result.c_str()); } int main() { return 0; };
4.生成对应的jni可执行文件,注意命名格式,linux结尾为.so, mac os结尾为.jnilib
linux:
gcc -Wall -fPIC -I./ -I/opt/jdk1.6.0_32/include -I/opt/jdk1.6.0_32/include/linux -shared -o libJNI.so com_pracbiz_JNIHelper.cpp -lstdc++
mac os:
gcc -Wall -fPIC -I./ -I/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers -shared -o libJNI.jnilib com_pracbiz_JNIHelper.cpp -lstdc++
-l是编译时的路径参数,编译JNI文件需要两个java提供的库文件,jni.h和jni_md.h,对于linux, jni.h在opt/jdk1.6.0_32/include, jni_md.h存在/opt/jdk1.6.0_32/include/linux, 对于mac os来说,这两个文件都在 /System/Library/Frameworks/JavaVM.framework/Versions/A/Headers目录下,不同的linux发行版以及不同的jdk版本可能位置会有所不同,这个在编译之前自己去确认下两个文件的路径。
5.文件生成好以后需要放到java.library.path,这样jvm才能加载到,那这个目录是什么呢,通过System.getProperty("java.library.path")方法就可以得到.
或者可以通过-Djava.library.path指定也行,下面会讲到。
6.应用很简单,写个TestJni.java,我是写在com.pracbiz.b2bportal.base.action包下面的.
system.out.println(JNIHelper.getInstance().exec("ls -la"));
以linux平台为例,如果so文件没有放到java.library.lib下,则运行时通过-Djava.library.path指定.so文件的路径
java -Djava.library.path=/home/oyl-admin/b2bportal/EC-Portal/branches/fp-phase2-client/web/WEB-INF/classes com.pracbiz.b2bportal.base.action.TestJni
如果已经放到java.library.lib下,则直接运行
java com.pracbiz.b2bportal.base.action.TestJni