`
BurningFlame
  • 浏览: 5468 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

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

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

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

要弄清楚这个问题, 首先得知道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动态加载:
  • 大小: 13.4 KB
分享到:
评论
12 楼 longhumentmj 2012-03-19  
一开始不知道是什么意思,但是看了楼主这篇文章后大概理解了,如果有一个代码小例子的话就更好了...
11 楼 BurningFlame 2010-05-22  
呵呵, 非常感谢大家的关注和解答.
huaiyude06 写道
你试着写一个用c调用c++的动态链接库,你就自然明白java怎样调用本地方法了,其实也是加载动态库,然后查找其中的名字,所以本地方法的名字编写就要规定了

但其实话题的重点是弄清楚Java/JVM是如何调用Native Method的原理, 并不是如你所讲的如何书写代码(或者说如何应用).
我从你的留言中看到一点, 我很欣赏, 就是认同了Java调用动态链接库与C调用动态链接库并没区别, 我很高兴.

whaosoft 写道
他本身就是c和c++写的 当然执行Native Method也没问题

大家也不要认为C/C++就理所应当地该支持调用动态链接库, 而不去深究他们是如何调用动态链接库的.
也可以同问, C/C++做为一种高级语言, 何以能够对机器码做任何处理?
套用主贴的结论, 同样做为高级语言, 用它们编写的程序能够调用动态链接库, 其功能完完全全是由操作系统完成的。 而其中涉及到调用动态链接库的代码, 发挥的作用,仅仅是告诉操作系统说程序执行到某处时要调用某个动态链接库中的某个函数。

其实简单来说就只有两句话, 完全按逻辑推导出来的:
既然动态链接库都已经是机器码了, 能够识别并执行它的也就只有操作系统了, 我相信大家对这一点应该是不会有疑问的吧(有疑问的话, 可以参考3楼回帖).
那好, 能够完成程序(不管用什么语言写成)调用动态链接库的功能的, 也就只能是操作系统了.

10 楼 huaiyude06 2010-05-22  
BurningFlame 写道
whaosoft 写道
他本身就是c和c++写的 当然执行Native Method也没问题

哈哈,谢谢! 你提醒我了!
我打算去查查资料, 看看C/C++调动态链接库是怎么实现的, 会对理解这个问题有很大帮助。

顺便说一句, 如果套用主贴的思维模式的话, 我会觉得C/C++调用动态链接库的过程, 也是: C/C++代码被编译成可执行文件先, 后面就跟主贴里讲的EXE调DLL一样了。

你试着写一个用c调用c++的动态链接库,你就自然明白java怎样调用本地方法了,其实也是加载动态库,然后查找其中的名字,所以本地方法的名字编写就要规定了
9 楼 jwx0925 2010-05-22  
我来回帖,虽然也不太明白原理,但是看了你的文章还是有启发的!谢谢
8 楼 BurningFlame 2010-05-22  
呵呵, 本来只是一篇发来期待和大家有个热烈讨论的帖子, 结果看的人多, 投隐藏的比回贴的多多了.
有人投隐藏, 应该意味着有很足够的把握认为这篇帖子的观点是错误的而且明显是误导大家的, 而且还不少, 可是却没见有人针对这个问题发表一些系统的能够自圆其说的观点.
那这么理解投隐藏的人, 不知道恰当不:
不理解编译原理和操作系统, 对Java盲目崇拜, 不求进步. 更有甚者可能认为我污蔑了Java在他们心目中的神圣形象.
而最重要的, 他们居然不知道如何表达自己的观点.
7 楼 BurningFlame 2010-05-21  
whaosoft 写道
他本身就是c和c++写的 当然执行Native Method也没问题

哈哈,谢谢! 你提醒我了!
我打算去查查资料, 看看C/C++调动态链接库是怎么实现的, 会对理解这个问题有很大帮助。

顺便说一句, 如果套用主贴的思维模式的话, 我会觉得C/C++调用动态链接库的过程, 也是: C/C++代码被编译成可执行文件先, 后面就跟主贴里讲的EXE调DLL一样了。
6 楼 whaosoft 2010-05-21  
他本身就是c和c++写的 当然执行Native Method也没问题
5 楼 BurningFlame 2010-05-21  
为什么大家不发表自己对这个问题的理解呢?
大家是不懂这方面吗, 还是不屑, 还是觉得只做应用就好不需要深究这些底层的东西, 还是盲目崇拜Java和JVM?

我想知道对这个问题的系统的能够自圆其说的解释, 最重要的, 得是正确的。
4 楼 BurningFlame 2010-05-21  
我真的很困惑Java到底是怎么执行Native Method的.

做为一种高级语言, 何以能够对机器码做任何处理?

想来想去, 就想到这一种方式.

大家来各抒己见吧.
3 楼 BurningFlame 2010-05-21  
谢谢你的解答!
引用
Java编译后的ByteCode与操作系统是没关系的,也不会被操作系统执行。
Java与操作系统的交互必然是通过JVM作为代理。

你这样说, 并没错. 但其实和我说的并不是一个意思.

其实编译原理中都讲过, 一种新生语言何以被操作系统所识别并运行?
对, 就是借助于编译器, 用以把新生语言翻译成已经存在的语言.

比如说,一种语言, 他的编译器绝大部分是用该语言自身写成的, 但是其核心部分一定是用其它已有语言(我们就假想是C好了)写成.

那C又何以被操作系统所识别并运行?

C的编译器核心部分可能是用汇编写的.

而汇编的编译器就把汇编代码翻译成了机器码.

所以不管中间的步骤怎么样, 一段代码不管用什么语言写成, 最终总要被翻译成机器码, 才能运行于操作系统上.

Java号称"一次编译, 处处运行", 但是也逃不出这个框框.

针对不同的操作系统, JVM的实现就不一样. 为什么不一样呢, 因为它就是用来把"一次编译, 处处运行"的ByteCode翻译成特定于该操作系统的机器码的.

我不知道这样说清楚了吗
2 楼 deadcode 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

至于应用挂掉的原因,看程序是怎么写的了。
1 楼 BurningFlame 2010-05-20  
希望懂这方面的高手给个明确的判定, 对还是错啊!

相关推荐

    JAVA调用C++的dell应用例子

    Jni(Java Native Interface)是sun提供的java与系统中的原生方法交互的技术(在windows\linux系统中,实现java与native method互调)。目前只能由c/c++实现。后两个都是sourceforge上的开源项目,同时也都是基于jni...

    Java调用动态链接库(Java 调用 DLL)

    Java本身不支持直接调用DLL,但可以通过JNI(Java Native Interface)或者第三方库如JNA(Java Native Access)来实现这一功能。 首先,我们来看JNI。JNI是Java平台标准的一部分,它为Java程序员提供了一种安全、...

    JAVA调用DLL方法 JAVA调用DLL方

    在Java中调用DLL文件主要通过Java Native Interface (JNI)、JAWINJNative和JNA等技术来实现。这些技术允许Java程序与本地代码进行交互,从而实现对DLL文件的调用。 #### JNI (Java Native Interface) JNI是Java...

    java调用C#封装的dll方法

    其中一种方案是使用Java Native Access (JNA) 来调用通过C++封装的C# DLL文件。 **步骤详解:** **1. 创建C# COM组件:** - **新建项目:** 在Visual Studio中创建一个新的类库项目,并命名为`COMTest`。 - **...

    java的native关键字学习

    通过JNI,Java程序可以调用C/C++函数,同时C/C++也可以调用Java的方法。以下是一些关于JNI和`native`关键字的核心知识点: 1. **JNI头文件生成**:在编写Java类并声明`native`方法后,我们需要使用`javah`工具生成...

    Java中native方法学习

    Native方法是Java编程语言中的一个特性,允许Java代码调用非Java代码(通常是C或C++编写的),这为Java应用程序提供了一个与本地操作系统和其他原生库交互的接口。这种能力对于那些需要高性能或特定平台功能的应用...

    [测试通过]JAVA调用第三方DLL的简单方法:JNA及DEMO

    Java Native Access (JNA) 是一个流行的开源框架,它允许Java代码直接调用本机库函数,而无需编写JNI(Java Native Interface)代码。本文将详细介绍如何使用JNA在Java中调用第三方DLL以及提供的DEMO示例。 首先,...

    Java调用DLL源代码

    4. **调用函数**:现在你可以像调用Java方法一样调用DLL中的函数了。 示例代码: ```java public interface MyDLL extends Library { int add(int a, int b); } MyDLL dll = (MyDLL) Native.loadLibrary("mydll",...

    Java通过JNA调用系统API

    通过理解JNA的工作原理,以及如何定义接口和结构体来映射原生函数,你可以轻松地在Java中调用`Kernel32.dll`或其他系统库中的函数。记住,合理使用并注意安全性和性能优化,是成功使用JNA的关键。

    pos机java调用程序demo(基于dll调用)

    Java本身并不直接支持调用本地DLL库,但通过Java Native Interface (JNI) 或第三方库如JNA(Java Native Access)可以实现。在这个项目中,开发者可能使用了JNA,因为它允许更简洁的API和无需编写C语言的头文件和...

    Java调用SPSS的实例

    首先,了解Java调用SPSS的基本原理:IBM SPSS Statistics提供了一套名为SPSSINC Java插件的API,它允许Java程序直接与SPSS会话进行交互。这个插件包含了一系列Java类,通过这些类,开发者可以创建、读取、写入和执行...

    基于JNA的java调用DLL动态库实例

    在Java编程环境中,有时我们需要利用C++编写的DLL动态链接库功能,特别是在处理底层系统调用或硬件交互时。本文将详细介绍如何通过Java Native Access (JNA) 库来实现Java调用DLL动态库,以"NetSdk.dll"为例进行实战...

    java调用dll最简单的方法

    在Java中调用DLL(Dynamic Link Library)文件,可以使用Java的本地方法接口(JNI,Java Native Interface)来实现。JNI允许Java程序与本地代码进行交互,从而实现跨平台的功能。

    java调用chrome浏览器内核cef实现,非jxbrowser

    Java调用Chrome浏览器内核是开发桌面应用时一个常见的需求,尤其在需要嵌入Web页面或者与Web内容交互的场景下。CEF(Chromium Embedded Framework)是一个开源项目,它允许开发者将Google Chrome的Blink渲染引擎和V8...

    DELPHI 7 调用 JAVA 接口

    首先,理解Delphi 7调用Java接口的基础原理。这种通信通常依赖于Java的本地接口(JNI,Java Native Interface),它允许Java代码调用C/C++代码,而Delphi代码可以编译为C++兼容的库。因此,Delphi通过JNI桥接,可以...

    Java调用c++类对象

    这种技术通常依赖于Java Native Interface (JNI),它允许Java代码直接调用本地(如C++)代码,反之亦然。下面我们将深入探讨如何通过JNI在Java中调用C++类对象以及涉及的关键知识点。 首先,我们需要理解JNI的概念...

    java调用C++动态链接库dll接口

    4. 调用C++函数:现在,你可以像调用Java方法一样调用C++库的函数了。 ```java int result = lib.downloadRecording("recording.mp4", 1642404000, 1642407600); ``` 5. 错误处理:由于JNA是直接调用本地代码,错误...

    非常好用java调用c++ dll文件demo

    Java本身并不直接支持调用C++代码,但可以通过JNI(Java Native Interface)来实现。JNI提供了一种方式让Java代码能够调用本地(native)代码,包括C和C++。这需要编写一个JNI头文件,定义C/C++函数的原型,然后编写...

    java调用json参数的webservice

    在探讨Java调用带有JSON参数的WebService之前,我们首先需要了解几个关键的技术概念:Java、JSON以及WebService。 Java是一种广泛使用的编程语言,它具有面向对象、跨平台、多线程以及健壮性等特点。Java在企业级...

    java后端调用大华视频的demo

    1. **Java Native Interface (JNI)**:由于大华SDK可能是用C或C++编写的,Java后端需要通过JNI来调用这些原生库。JNI允许Java代码直接调用本地(非Java)代码,实现跨语言交互。 2. **大华SDK**:大华提供了一套...

Global site tag (gtag.js) - Google Analytics