`

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

jni 
阅读更多
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 __cplusplus
extern "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"
EXPORTS
Java_HelloWorld_120111226_printHelloWorld
Java_HelloWorld_120111226_add
Java_LC_TestJNI_printInt
Java_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=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [MaxflowJNIInterface.dll+0x1a74]  Graph<long,long,__int64>::add_edge+0x74

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
J  GraphMinimization.GraphCut.addTerm2(IIIIII)V
J  app.StereoCorrespodenceUsingGraphCut.generateStereoCorrespodenceGraph(Llc/util/image/IntPair;)LGraphMinimization/GraphCut;
j  app.StereoCorrespodenceUsingGraphCut.calculate()V+52
j  app.StereoCorrespodenceUsingGraphCut.main([Ljava/lang/String;)V+62
v  ~StubRoutines::call_stub

  • 大小: 100.5 KB
  • 大小: 35 KB
  • 大小: 16.9 KB
  • 大小: 8 KB
  • 大小: 18.5 KB
  • 大小: 21.1 KB
  • 大小: 114.7 KB
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics