该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2010-05-20
最后修改:2010-05-23
做为一种高级语言, 何以能够对机器码做任何处理? 想来想去, 就只想到本文所述的这一种方式而已. 本文仅涉及原理方面, 其中猜测成分过重, 以期抛砖引玉, 欢迎大家抛玉. 要弄清楚这个问题, 首先得知道Native Method到底是什么, 它以什么形式存在, 它怎么样被使用。 知道这些, 离问题的答案就近了一步。 native方法 以Windows上鼎鼎大名的DLL作为代表. 源起 Java应用调用SAP RFC传递大量数据时, 随着过程的进行, 该Java应用对其它任务的响应速度变慢, 严重时甚至会导致Java应用core dump。 Java应用和SAP都是跑在各自的Unix服务器上, 所以Java应用调用SAP RFC时, 首先是调用本地的SAP Client, 这个东东在Unix上应该是以动态链接库形式存在的. 我查了下, 在Unix上, 动态链接库习惯以 .so 为文件名结尾(通常还以 lib 开头)。 何为DLL? DLL是Dynamic Link Library的缩写,意为动态链接库。 比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。 这些子模块和通用模块, 我们倾向于把它们单独各自编译成DLL。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以DLL模块的形式实现。 DLL vs EXE 从上面可以看出, DLL与EXE只是分工不同而已。 EXE加载后作为进程的主体运行,DLL要加载到一个进程中作为一个模块运行。 他们没有本质的区别。 DLL事实上和EXE文件一样,同属PE格式的执行文件(通俗地讲,机器码。 说明一下, 这里的机器指的是操作系统包装下的机器, 不是指裸机。下同)。只是有个标志位不一样, 用以区分两者。 Java如何调用DLL? ![]() 既然DLL为机器码, Java作为一种高级语言,自然对其无能为力。 对于Java调用DLL只能在操作系统级别解释。 Java代码被编译运行在JVM上时, 根据编译原理, 本质上, Java代码最终总要被翻译成机器码,才能运行在操作系统上(此处也许没说清楚吧, 请看3楼的回帖,详细解释了)。 其实放到操作系统级别来看, JVM也只是运行于其上的一个进程, 而Java应用借助于JVM运行, 就表现为JVM这个进程中的若干个线程, 而调用DLL 就是这个进程中某个线程去调用了存在于代码区的另一段机器码(帖子最后引用了<<WINDOWS核心编程>>, 可以帮助理解)。 所以我们常说的Java调用DLL, 准确地说是JVM调用DLL, 其功能完完全全是由操作系统完成的, 其本质和EXE调用DLL绝无二致。 而JNI在其中的功能,仅仅是告诉操作系统说程序执行到某处时要调用某个动态链接库中的某个函数。 说到这里, 那么关于Java调用DLL时, DLL使用的堆和栈空间是额外申请的, 还是占用的JVM的主存,自然也就不言自明了。 那么, 当Java应用调用SAP RFC传递大量数据时, 会导致Java应用core dump, 也就不难解释了. 原因很简单, JVM上同时运行着大大小小若干个Job, 其内存参数设置不足够大, 陆续为传递过来的数据分配极大量空间而又不能释放,以致于内存耗尽. 如果在调用Native Method过程中JVM能够存活下来, 那么随后Native Method返回时, Java会将返回的数据封装成Java能识别的类型 - Object或其子类, 这就又需要一倍于刚才的空间. JVM在这里挂掉的可能性就大些了。 PS 如若果真如此, 那任何通用型编程语言支持Native Method从实现上来说,简直是再简单不过了。 而Java支持Native Method, 谈不上任何闪光之处。 知识点 引用自<<WINDOWS核心编程>> 在应用程序(或另一个DLL)能够调用DLL中的函数之前,DLL文件映像必须被映射到调用进程的地址空间中。一旦DLL的文件映像被映射到调用进程的地址空间中, DLL的函数就可以供进程中运行的所有线程使用。对于进程中的线程来说,DLL的代码和数据看上去就像恰巧是在进程的地址空间中的额外代码和数据一样。当一个线程调用DLL函数时,该DLL函数要查看线程的堆栈,以便检索它传递的参数,并将线程的堆栈用于它需要的任何局部变量。此外,DLL中函数的代码创建的任何对象均由调用线程所拥有,而DLL本身从来不拥有任何东西。 DLL动态加载: ![]() 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2010-05-20
希望懂这方面的高手给个明确的判定, 对还是错啊!
|
|
返回顶楼 | |
发表时间:2010-05-21
引用 Java如何调用DLL?
既然DLL为机器码, JVM当然对其无能为力。 引用 Java代码被编译运行在JVM(JVM也不过是个运行在操作系统上的EXE而已)上时, 本质上相当于Java代码被编译成机器码运行在操作系统上。 Java调用DLL也就是Java程序被编译成机器码后最终和DLL一起被操作系统执行, 其本质和EXE调用DLL绝无二致。
窃以为楼主的认识有些偏差。Java编译后的ByteCode与操作系统是没关系的,也不会被操作系统执行。 Java与操作系统的交互必然是通过JVM作为代理。 可以参考这 http://www.iteye.com/topic/304594 至于应用挂掉的原因,看程序是怎么写的了。 |
|
返回顶楼 | |
发表时间:2010-05-21
最后修改:2010-05-21
谢谢你的解答!
引用 Java编译后的ByteCode与操作系统是没关系的,也不会被操作系统执行。
Java与操作系统的交互必然是通过JVM作为代理。 你这样说, 并没错. 但其实和我说的并不是一个意思. 其实编译原理中都讲过, 一种新生语言何以被操作系统所识别并运行? 对, 就是借助于编译器, 用以把新生语言翻译成已经存在的语言. 比如说,一种语言, 他的编译器绝大部分是用该语言自身写成的, 但是其核心部分一定是用其它已有语言(我们就假想是C好了)写成. 那C又何以被操作系统所识别并运行? C的编译器核心部分可能是用汇编写的. 而汇编的编译器就把汇编代码翻译成了机器码. 所以不管中间的步骤怎么样, 一段代码不管用什么语言写成, 最终总要被翻译成机器码, 才能运行于操作系统上. Java号称"一次编译, 处处运行", 但是也逃不出这个框框. 针对不同的操作系统, JVM的实现就不一样. 为什么不一样呢, 因为它就是用来把"一次编译, 处处运行"的ByteCode翻译成特定于该操作系统的机器码的. 我不知道这样说清楚了吗 |
|
返回顶楼 | |
发表时间:2010-05-21
我真的很困惑Java到底是怎么执行Native Method的.
做为一种高级语言, 何以能够对机器码做任何处理? 想来想去, 就想到这一种方式. 大家来各抒己见吧. |
|
返回顶楼 | |
发表时间:2010-05-21
最后修改:2010-05-21
为什么大家不发表自己对这个问题的理解呢?
大家是不懂这方面吗, 还是不屑, 还是觉得只做应用就好不需要深究这些底层的东西, 还是盲目崇拜Java和JVM? 我想知道对这个问题的系统的能够自圆其说的解释, 最重要的, 得是正确的。 |
|
返回顶楼 | |
发表时间:2010-05-21
他本身就是c和c++写的 当然执行Native Method也没问题
|
|
返回顶楼 | |
发表时间:2010-05-21
whaosoft 写道 他本身就是c和c++写的 当然执行Native Method也没问题
哈哈,谢谢! 你提醒我了! 我打算去查查资料, 看看C/C++调动态链接库是怎么实现的, 会对理解这个问题有很大帮助。 顺便说一句, 如果套用主贴的思维模式的话, 我会觉得C/C++调用动态链接库的过程, 也是: C/C++代码被编译成可执行文件先, 后面就跟主贴里讲的EXE调DLL一样了。 |
|
返回顶楼 | |
发表时间:2010-05-22
最后修改:2010-05-22
呵呵, 本来只是一篇发来期待和大家有个热烈讨论的帖子, 结果看的人多, 投隐藏的比回贴的多多了.
有人投隐藏, 应该意味着有很足够的把握认为这篇帖子的观点是错误的而且明显是误导大家的, 而且还不少, 可是却没见有人针对这个问题发表一些系统的能够自圆其说的观点. 那这么理解投隐藏的人, 不知道恰当不: 不理解编译原理和操作系统, 对Java盲目崇拜, 不求进步. 更有甚者可能认为我污蔑了Java在他们心目中的神圣形象. 而最重要的, 他们居然不知道如何表达自己的观点. |
|
返回顶楼 | |
发表时间:2010-05-22
我来回帖,虽然也不太明白原理,但是看了你的文章还是有启发的!谢谢
|
|
返回顶楼 | |