高分求教

whos2002110 2014-09-10 10:16:20
加精
系统里面有个计算需要借助matlab程序实现。 但使用过程中发现频繁调用matlab导致调用越来越慢。

下面是一个简单的测试例子,计算两个数四则运算结果, 测试引入了matlab工具生成的myCal.jar及matlab java编程所需的工具包。 MyCal对象提供了matlab函数的主调用方法myCal, MyCal构造较慢未计入耗时统计。

代码里循环调用myCal方法, 每1w次打印出这1w次调用所消耗的时间,结果显示越往后耗时越久。 执行过程中通过jconsole查看jvm内存及垃圾回收并无异常。

这是我看到的一段关于jni调用的说法:

“使用本机代码编写应用程序的一部分,特别是频繁使用的部分,并将之与 Java 链接,这样做通常是为了提高性能。不过,JVM 与本机代码之间的通信通常很慢,因此,太多的 JNI 调用可能会降低性能。只要有可能就应该将本机操作集合在一起,以减少 JNI 调用的数量”

测试代码:


import com.mathworks.toolbox.javabuilder.MWException;

import myCal.MyCal;

public class CalTest {

static MyCal myCal;
static {
try {
myCal = new MyCal();//matlab计算对象
} catch (MWException e) {
e.printStackTrace();
}
}

static void cal() throws MWException {
long t0 = System.currentTimeMillis();
for (int i = 1; i <= 30000; i++) {
//调用matlab函数计算结果(jni调用)
Object[] calResult = myCal.myCal(4, 2, 3);

if ((i % 10000) == 0) {
long t1 = System.currentTimeMillis();
//每1w次打印执行时间, 发现调用越多则调用越慢
System.out.println("第" + (i / 10000) + "w用时:" + (t1 - t0) / 1000);
t0 = t1;
}
}
}

public static void main(String[] args) throws Exception {
cal();
Thread.sleep(30000);
System.out.println("=====");
cal();
}
}


有没有相关经验给分析呀,如何解决这个问题, 感激不尽
...全文
2040 33 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
kunkunqian 2014-09-17
  • 打赏
  • 举报
回复
skgary 2014-09-15
  • 打赏
  • 举报
回复
其实就是这个测试产生的垃圾内存,JVM根本来不及收集的意思?
whos2002110 2014-09-15
  • 打赏
  • 举报
回复
正确调用的代码是这样的: 在使用完计算结果 Object[] calResult; 后加入 MWArray.disposeArray(calResult); 这么一句话。就是

for (Object o : calResult) {
        		MWNumericArray m = (MWNumericArray) o;
        		m.dispose();
        	}
通过debug发现 calResult 实际类型是MWNumericArray, 这个是matlab转为java后的一种数据类型(矩阵、向量、数值), 里面的一个NativeArray 很明显就是matlba 的数据(byte[])。 NativeArray 的 finalize方法被重写调用dispose()。 上面m.dispose(); 也就是调用内部NativeArray 的dispose()。 看到这里大家获取有些疑惑, 因为finalize方法被垃圾回去的时候会自动被调用,也就是说calResult 出了作用域以后即会被调用dispose方法, 我们无需加入上面的代码。 我也真实因为这个观点才犯错的。 这里有篇文章对于finalize可能引发内存溢出 http://ju.outofmemory.cn/entry/74671 在例子(生产的例子不是测试例子)中并不会内存溢出(jvm设置的内存比较大), 但问题确实是Finalizer线程比主线程优先级低,当这么大的一直循环创建了大量Finalizer对象, 却没能被调用执行。 这个我通过jmap弄出dump文件后证实确实如此, 在测试内存快慢的的时候几乎全被Finalizer对象占有。 手动调用dispose后正确解决了这个问题。想起之前看到Java编程思想还是jvm那本书里说 java程序员应该完全忘记finalize方法。 在国外网上查到所有调用matlab的例子中都会像上面显示调用dispose, 然后带句注释 //clean up the resources used by the generated MATLAB code. 获取 //free native resources 并没说dispose最终做了什么, 反编译出的代码里面是native调用。 我猜测是java调用Matlab使用了Direct Memory 然后我通过-XX:MaxDirectMemorySize=1M测试无变化,应该也不是Direct Memory被大量占用的问题。 目前就知道这些东西, 问题已经解决, 但我还是不知道Java调用matlab机制是什么, dispose的native方法到底做了什么。
skgary 2014-09-15
  • 打赏
  • 举报
回复
那会不会是dispose产生了一个无法多线程工作现象呢?
帝瓜 2014-09-15
  • 打赏
  • 举报
回复
mark一下
whos2002110 2014-09-15
  • 打赏
  • 举报
回复
引用 29 楼 skgary 的回复:
[quote=引用 28 楼 whos2002110 的回复:] [quote=引用 27 楼 whos2002110 的回复:] [quote=引用 26 楼 skgary 的回复:] 其实就是这个测试产生的垃圾内存,JVM根本来不及收集的意思?
不是jvm内存[/quote] 可能我没说清楚, 慢的问题解决了,但原因还不知道。 上面只是说 finalize方法的一些东西。 大量的Finalizer并不是慢的原因。[/quote] 其实,我一直很好奇你原来的代码中 gc的情况到底 是如何的。 照这个文章的说法,应该分析蛮透的了啊。 finalize的时候还要通过JNI去调用,而那个文章说一旦finalize有内容的话,又会直接到FGC上面去。 这样,FGC相关的参数就会对性能影响很大了。[/quote] 频繁full gc肯定是不行的, 测试是也确实如此,应为不管新生代还是老生代都是一会就满了(我设的值小),全被Finalizer占了没办法只能full gc,并不是因为finalize。 matlab的工具包作者有意或者好心重写了finalize方法, 在里面做了开发人员应该手动调用的 dispose。 但这个好心并不能完全奏效,原因就是那篇文章说的, 出现这种情况是因为太频繁创建重写了finalize的对象,Finalizer线程跟不上了。 对于我生产中也确实产生了大量的Finalizer, 但这对于我服务器jvm配置还是小菜一碟, 我但是测试跑了几乎一个下午jvm老生代也没满呢。 问题就是dispose 里面的jni调用必需手动及时的做。 它里面是清理的matlab的一些东西。
skgary 2014-09-15
  • 打赏
  • 举报
回复
引用 28 楼 whos2002110 的回复:
[quote=引用 27 楼 whos2002110 的回复:] [quote=引用 26 楼 skgary 的回复:] 其实就是这个测试产生的垃圾内存,JVM根本来不及收集的意思?
不是jvm内存[/quote] 可能我没说清楚, 慢的问题解决了,但原因还不知道。 上面只是说 finalize方法的一些东西。 大量的Finalizer并不是慢的原因。[/quote] 其实,我一直很好奇你原来的代码中 gc的情况到底 是如何的。 照这个文章的说法,应该分析蛮透的了啊。 finalize的时候还要通过JNI去调用,而那个文章说一旦finalize有内容的话,又会直接到FGC上面去。 这样,FGC相关的参数就会对性能影响很大了。
whos2002110 2014-09-15
  • 打赏
  • 举报
回复
引用 27 楼 whos2002110 的回复:
[quote=引用 26 楼 skgary 的回复:] 其实就是这个测试产生的垃圾内存,JVM根本来不及收集的意思?
不是jvm内存[/quote] 可能我没说清楚, 慢的问题解决了,但原因还不知道。 上面只是说 finalize方法的一些东西。 大量的Finalizer并不是慢的原因。
whos2002110 2014-09-15
  • 打赏
  • 举报
回复
引用 26 楼 skgary 的回复:
其实就是这个测试产生的垃圾内存,JVM根本来不及收集的意思?
不是jvm内存
qqqaping 2014-09-14
  • 打赏
  • 举报
回复
谢谢大家的回复, 问题已经解决, 但我还没搞清楚根本的原因, 等我测试出结果再贴出来与大家分享。
qq_20691895 2014-09-12
  • 打赏
  • 举报
回复
JVM 与本机代码之间的通信通常很慢,因此,太多的 JNI 调用可能会降低性能
老衲是光头 2014-09-12
  • 打赏
  • 举报
回复
whos2002110 2014-09-12
  • 打赏
  • 举报
回复
谢谢大家的回复, 问题已经解决, 但我还没搞清楚根本的原因, 等我测试出结果再贴出来与大家分享。
eeight 2014-09-12
  • 打赏
  • 举报
回复
我在MT4中调用过matlab生成的DLL,调用速度的问题倒是没怎么留意, 调用matlab只是为了验证matlab里提供的东西能不能解决我的问题, 后来发现可以解决,就把matlab里的东西用JAVAl来实现, 里面的东西大多有其他语言的替代实现,LZ可以找找
-xice- 2014-09-11
  • 打赏
  • 举报
回复
你这一堆static,问题出在大作用域的MyCal里。建议你查看MyCal里的代码,是否存在未释放的资源啥的,或者在重复执行时影响执行效率的东东
  • 打赏
  • 举报
回复
把静态去掉 换成new的方式试试
teemai 2014-09-10
  • 打赏
  • 举报
回复
在 Object[] calResult = myCal.myCal(4, 2, 3); 前后打印耗时时间看下效果
小紧张 2014-09-10
  • 打赏
  • 举报
回复
那就得看myCal里面了
whos2002110 2014-09-10
  • 打赏
  • 举报
回复
引用 4 楼 huasuoworld 的回复:
你有没有考虑System.currentTimeMillis(); 所花费的时间,你打出来的时间是JNI的执行时间还是java方法和JNI一起执行的时间? 你是线程睡眠后再执行的第二个方法,你拆开执行看看所耗时间。
引用 5 楼 z3453876 的回复:
代码没看出什么问题,关注一下
引用 6 楼 fangmingshijie 的回复:
Object[] calResult = myCal.myCal(4, 2, 3);这个是多线程还是单线程?有无线程安全问题?有无同步问题?
我现在初步确定了问题在返回值这块, Object[] calResult = myCal.myCal(4, 2, 3); 这个第一个参数是一个int 表示获几个返回值, 可以比matlab 函数返回值个数小, 同时也是calResult 数组的长度。 当我不获取返回值也就是Object[] calResult = myCal.myCal(0, 2, 3); 测试打印的时间稳定在2秒, 比较短且不会增长
whos2002110 2014-09-10
  • 打赏
  • 举报
回复
引用 3 楼 gaofuqi 的回复:
这个倒没有研究过,楼主可以把整个工程发出来吗?我也想看看。
就这么多代码,另外有两个jar, 给你也测试不了, 必需装matlab环境才能跑。
加载更多回复(12)

62,634

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧