首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > VSTS >

JNI学习笔记,含VS配置x64平台的有关问题

2012-10-27 
JNI学习笔记,含VS配置x64平台的问题1、来个java程序,本地方法前加native关键字public class HelloWorld_201

JNI学习笔记,含VS配置x64平台的问题
1、来个java程序,本地方法前加native关键字

public class HelloWorld_20111226 {public static native void printHelloWorld();public static native int add(int a, int b);static {System.loadLibrary("TestJNI_201112");}public static void main(String[] args) {printHelloWorld();int sum = add(1, 2);System.out.println(sum);}}


2.生成C++头文件
命令行下 javah 类名(在.class的根路径下  报名.类名,无需后缀)

简单方法见http://cherishlc.iteye.com/blog/1326893
生成的头文件如下
/* DO NOT EDIT THIS FILE - it is machine generated */#include <jni.h>/* Header for class HelloWorld_20111226 */#ifndef _Included_HelloWorld_20111226#define _Included_HelloWorld_20111226#ifdef __cplusplusextern "C" {#endif/* * Class:     HelloWorld_20111226 * Method:    printHelloWorld * Signature: ()V */JNIEXPORT void JNICALL Java_HelloWorld_120111226_printHelloWorld  (JNIEnv *, jclass);/* * Class:     HelloWorld_20111226 * Method:    add * Signature: (II)I */JNIEXPORT jint JNICALL Java_HelloWorld_120111226_add  (JNIEnv *, jclass, jint, jint);#ifdef __cplusplus}#endif#endif



3.写C++端的实现
新建vs的win32工程:


接下来选择DLL工程:

加入刚刚生成的头文件;写实现函数的cpp文件,写导出函数的.def文件:



#include "HelloWorld_20111226.h"#include <iostream>JNIEXPORT void JNICALL Java_HelloWorld_120111226_printHelloWorld( JNIEnv *, jclass ){std::cout<<"Hello world"<<std::endl;}JNIEXPORT jint JNICALL Java_HelloWorld_120111226_add( JNIEnv *, jclass, jint a, jint b){return a+b;}


注意:64位的JVM需要64位的DLL!!
设置方法: VS下设置如下:
点击工具栏上的配置编译的平台的工具栏的向下的箭头:

选择所需工程,点击之:

选择x64架构,点ok,搞定!!

注意:jni.h的路径要加进来,你懂的:



注意:还是老老实实用.def文件定义导出函数吧!不这样函数名可能会被编译器改掉!!!
//main.def文件如下:LIBRARY "TestJNI_201112"EXPORTSJava_HelloWorld_120111226_printHelloWorldJava_HelloWorld_120111226_addJava_LC_TestJNI_printIntJava_LC_TestJNI_printIntArray



4.编译,将生成的dll文件考到当前路径下(在Eclipse中运行即为工程文件所在路径),运行java程序,一切OK
注意:别忘了java类里要加载DLL“static {System.loadLibrary("TestJNI_201112");}”! 不带后缀!

5.进阶:
Jni中C++和Java的参数传递http://www.blogjava.net/china-qd/archive/2006/04/29/44002.html
Java Native Interface Specification:http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html

6.在Java中用C++的类:
只是想到一个小技巧:
声明一个所需类的全局指针变量,需要时new一下, 不需要时delete之;缺点是只能用一个啊! 当然用个vector之类的记录当前活动的自然可以,可是多了一层,速度受影响吧!!
部分代码如下:
#include "Maxflow/LCEnergyMinimize_Graph.h"#include "GraphMinimization_GraphCut.h"typedef LCEnergyMinimize_Graph<jint,jlong> GraphIntLong;GraphIntLong* g;JNIEXPORT void JNICALL Java_GraphMinimization_GraphCut_generateGraph( JNIEnv *, jobject ){if(g!=NULL)delete g;g=new GraphIntLong();}/* * Class:     GraphMinimization_GraphCut * Method:    releaseGraph * Signature: ()V */JNIEXPORT void JNICALL Java_GraphMinimization_GraphCut_releaseGraph  (JNIEnv *, jobject){  if(g!=NULL)delete g;  g=NULL;}/* * Class:     GraphMinimization_GraphCut * Method:    addVariable * Signature: (I)I */JNIEXPORT jint JNICALL Java_GraphMinimization_GraphCut_addVariable  (JNIEnv *, jobject, jint num){ return g->addVariable(num);}

7.调试记录:
一开始程序经常崩溃,只说是C++端的错误。
后来看到下面的error log,至少知道是Graph<long,long,__int64>::add_edge出错,后来发现其中有assert语句,检查下标越界,感觉是自己写的时候下标越界了,在java里调用add_edge的地方增添了句检查下标越界的操作,越界时抛出异常:throw new RuntimeException("x = "+x+"\ty = "+y+"\t varNum = "+getVarNum());
果然问题出在下标上!!!
后来发现自己存不同下标的变量太多,有一处弄混了!!
Stack: [0x0000000001ca0000,0x0000000001da0000],  sp=0x0000000001d9f750,  free space=1021kNative frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)C  [MaxflowJNIInterface.dll+0x1a74]  Graph<long,long,__int64>::add_edge+0x74Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)J  GraphMinimization.GraphCut.addTerm2(IIIIII)VJ  app.StereoCorrespodenceUsingGraphCut.generateStereoCorrespodenceGraph(Llc/util/image/IntPair;)LGraphMinimization/GraphCut;j  app.StereoCorrespodenceUsingGraphCut.calculate()V+52j  app.StereoCorrespodenceUsingGraphCut.main([Ljava/lang/String;)V+62v  ~StubRoutines::call_stub

热点排行