JNA的一个坑

本文地址:http://www.cnblogs.com/herbix/p/3537612.html

JNA是一个在java里调用dll或者so这种动态链接库的一个工具,和JNI相比,适应性更好,限制也比较小。不过相比JNI,JNA有一些坑,比如结构体格式不对很容易引起VM崩溃,而且没法调试,甚是头疼。用的时候还是一点一点移植,仔细检查,方能正确使用。

不过今天讲的不是这个坑,而是另一个坑。那是我在尝试用java使用本是C语言用的lua库(不要问我为什么这么蛋疼),代码如下:

 1 public class Main {
 2 
 3     public static void main(String[] args) {
 4         final LuaApi lua = LuaApi.instance;
 5         lua_State L = lua.luaL_newstate();
 6         lua.luaL_openlibs(L);
 7         
 8         LuaMacros.lua_register(L, "qksb", new lua_CFunction() {
 9             public int invoke(lua_State L) {
10                 System.out.println("before");
11                 
12                 lua.lua_pushvalue(L, 1);
13                 LuaMacros.lua_pcall(L, 0, 0, 0);
14                 
15                 System.out.println("after");
16                 return 0;
17             }
18         });
19     
20         String program = EasyFileAccess.loadFile(Main.class.getResourceAsStream("test.lua"), null);
21         
22         if(0 != LuaMacros.luaL_dostring(L, program))
23             System.out.println("Failed to invoke.
");
24         
25         lua.lua_close(L);
26     }
27 
28 }

这段程序的作用是为lua环境添加了一个叫qksb的函数,这个函数的内容在 new lua_CFunction(){} 里面进行了定义,可以在lua环境下调用。

但是运行时候发现刚开始这个函数还好好的,到后面发现调用了也没有任何效果,而lua环境下本来的函数没有受到任何影响。

最后我发现是java的垃圾回收机制把这个对象回收掉了,因为我在19行加入System.gc();以后这个函数从一开始就不行了。

为什么会出现这样的情况呢?因为JNA相关的每个对象在内部地址(相对于Java堆)中都有对应的空间,这个函数对象最终传入的是JNA调用的那个dll里面的函数lua_register,这个函数进行了引用,引用的对象也不是 new lua_CFunction(){} 这个对象,而是相应的内部地址的一个函数。这样 new lua_CFunction(){} 对象在java环境中的引用次数为0,被垃圾回收也不意外。

知道了问题所在,解决起来就很简单了。让这个对象在java环境中的引用不为0就好了,比如用一个List<lua_CFunction>把所有的注册函数保存下来就好了。

后记:博主已经放弃在java里使用lua了,因为依赖setjump和longjump的resume/yield机制无法在这种环境下运行。

原文地址:https://www.cnblogs.com/herbix/p/3537612.html