揭开Java调用Native Method的神秘面纱(纯原理)

我真的很困惑Java到底是怎么执行Native Method的.
做为一种高级语言, 何以能够对机器码做任何处理?
想来想去, 就只想到本文所述的这一种方式而已.

本文仅涉及原理方面, 其中猜测成分过重, 以期抛砖引玉, 欢迎大家抛玉.

要弄清楚这个问题, 首先得知道Native Method到底是什么, 它以什么形式存在, 它怎么样被使用。
知道这些, 离问题的答案就近了一步。

native方法 以Windows上鼎鼎大名的DLL作为代表.

[b]源起[/b]
Java应用调用SAP RFC传递大量数据时, 随着过程的进行, 该Java应用对其它任务的响应速度变慢, 严重时甚至会导致Java应用core dump。
Java应用和SAP都是跑在各自的Unix服务器上, 所以Java应用调用SAP RFC时, 首先是调用本地的SAP Client, 这个东东在Unix上应该是以动态链接库形式存在的. 我查了下, 在Unix上, 动态链接库习惯以 .so 为文件名结尾(通常还以 lib 开头)。

[b]何为DLL?[/b]
DLL是Dynamic Link Library的缩写,意为动态链接库。
比较大的应用程序都由很多模块组成,这些模块分别完成相对独立的功能,它们彼此协作来完成整个软件系统的工作。可能存在一些模块的功能较为通用,在构造其它软件系统时仍会被使用。 这些子模块和通用模块, 我们倾向于把它们单独各自编译成DLL。在运行时,只有当EXE程序确实要调用这些DLL模块的情况下,系统才会将它们装载到内存空间中。这种方式不仅减少了EXE文件的大小和对内存空间的需求,而且使这些DLL模块可以同时被多个应用程序使用。Windows自己就将一些主要的系统功能以DLL模块的形式实现。

[b]DLL vs EXE[/b]
从上面可以看出, DLL与EXE只是分工不同而已。
EXE加载后作为进程的主体运行,DLL要加载到一个进程中作为一个模块运行。

他们没有本质的区别。
DLL事实上和EXE文件一样,同属PE格式的执行文件(通俗地讲,机器码。 说明一下, 这里的机器指的是操作系统包装下的机器, 不是指裸机。下同)。只是有个标志位不一样, 用以区分两者。

[b]Java如何调用DLL?[/b]
[img]http://dl.iteye.com/upload/attachment/252626/79c5f6d3-1e7e-38c0-9090-b8b8f1e99587.jpg[/img]
既然DLL为机器码, Java作为一种高级语言,自然对其无能为力。
对于Java调用DLL只能在操作系统级别解释。

Java代码被编译运行在JVM上时, [b]根据编译原理, 本质上, Java代码最终总要被翻译成机器码,才能运行在操作系统上[/b]([b]此处也许没说清楚吧, 请看3楼的回帖,详细解释了[/b])。

[b]其实放到操作系统级别来看, JVM也只是运行于其上的一个进程, 而Java应用借助于JVM运行, 就表现为JVM这个进程中的若干个线程, 而调用DLL 就是这个进程中某个线程去调用了存在于代码区的另一段机器码(帖子最后引用了<<WINDOWS核心编程>>, 可以帮助理解)。[/b]
[b]所以我们常说的Java调用DLL, 准确地说是JVM调用DLL, 其功能完完全全是由操作系统完成的, 其本质和EXE调用DLL绝无二致。 而JNI在其中的功能,仅仅是告诉操作系统说程序执行到某处时要调用某个动态链接库中的某个函数。[/b]

说到这里, 那么关于Java调用DLL时, DLL使用的堆和栈空间是额外申请的, 还是占用的JVM的主存,自然也就不言自明了。

那么, 当Java应用调用SAP RFC传递大量数据时, 会导致Java应用core dump, 也就不难解释了.
原因很简单, JVM上同时运行着大大小小若干个Job, 其内存参数设置不足够大, 陆续为传递过来的数据分配极大量空间而又不能释放,以致于内存耗尽. 如果在调用Native Method过程中JVM能够存活下来, 那么随后Native Method返回时, Java会将返回的数据封装成Java能识别的类型 - Object或其子类, 这就又需要一倍于刚才的空间. JVM在这里挂掉的可能性就大些了。


[b]PS[/b]
如若果真如此, 那任何通用型编程语言支持Native Method从实现上来说,简直是再简单不过了。
而Java支持Native Method, 谈不上任何闪光之处。


[b]知识点[/b]
引用自<<WINDOWS核心编程>>
在应用程序(或另一个DLL)能够调用DLL中的函数之前,DLL文件映像必须被映射到调用进程的地址空间中。一旦DLL的文件映像被映射到调用进程的地址空间中, DLL的函数就可以供进程中运行的所有线程使用。对于进程中的线程来说,DLL的代码和数据看上去就像恰巧是在进程的地址空间中的额外代码和数据一样。当一个线程调用DLL函数时,该DLL函数要查看线程的堆栈,以便检索它传递的参数,并将线程的堆栈用于它需要的任何局部变量。此外,DLL中函数的代码创建的任何对象均由调用线程所拥有,而DLL本身从来不拥有任何东西。

DLL动态加载:
[img]http://dl.iteye.com/upload/attachment/252581/78776efb-45f2-3ed3-81da-18608b59dc98.gif[/img]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值