Java内存泄漏与本机C和Fortran代码

Man*_*dre 6 java memory fortran memory-leaks

我正在开发一个旧的java程序,其中包含一个带有Fortran调用的本机库.

所以,我有Java通过JNI调用C,然后调用Fortran.

在生产中,我们有一个内存不足的错误,如:

Native memory allocation (malloc) failed to allocate 120000 bytes for jfloat in C:\BUILD_AREA\jdk6_37\hotspot\src\share\vm\prims\jni.cpp
Run Code Online (Sandbox Code Playgroud)

我怀疑是内存泄漏.

我是公司的新手,我想在linux上工作,但他们让我在Windows上工作:(在生产中我们使用.so文件,因为我们在solaris上,我在Windows上使用DLL(逻辑上).

首先,我试图重现生产问题.因此,我创建了一个单元测试,它加载DLL并调用多次调用本机方法的java类.当我这样做时,我看到processExplorer.exe,内存每2秒增长到2MB.我在生产中也有例外.

我很高兴我成功地重现了这个问题,我可以说问题来自C或Fortran Code.

接下来,我尝试删除对Fortran的调用,我的java只调用C(没有Fortran,这个测试允许我查看问题是来自C还是Fortran.)

结果是记忆没有移动!凉!我可以说我对C中的malloc/free没有任何问题.

所以,我决定学习一点Fortran来查看代码.:)

我了解到在Fortran中我们可以使用allocate和deallocate关键字来玩内存.我的代码不包含这些关键字.:(

在所有这些之后,有人让我访问Solaris以启动我的junit测试,该测试调用Java-> JNI-> C => Fortran并使用.so而不是DLL.

而且意外 - 记忆没动!我在Solaris或RedHat下没有任何问题.

我被困了,因为生产中存在问题,但我无法清楚地重现它.:(

为什么我看到DLL和SO之间的区别?代码(java/C/Fortran)完全相同,因为编译它的是我.

我该如何调查更多?

我试图在Windows下进行内存转储,我重现了这个问题,但我什么也没看到.

是jvm中的问题吗?或者问题可能在通过JNI传递给C的对象中?

非常感谢帮助我解决这个问题.

信息:我使用的是Windows 7 64位

PS:我是法国人,请原谅我的英语.我每次都尽力做到最好.;)

这是C代码的标题:

    #ifndef unix 
       __MINGW_IMPORT void modlin_OM(float pmt[], float abaque[][], float don[][], float cond[], float res[][], int flag[]) ; 
    #else 
       extern void modlin_om_(float * pmt, float * abaque, float * don, float * cond, float * res, int * flag) ; 
    #endif
Run Code Online (Sandbox Code Playgroud)

并且在方法之后:

   JNIEXPORT jint JNICALL Java_TrtModlin_modlin_1OM
     (JNIEnv * env, jobject obj, 
 jfloatArray pmtPar, 
 jobjectArray abaquePar, jobjectArray donPar, jfloatArray condPar, jobjectArray resPar,  jintArray flagPar)
   {
Run Code Online (Sandbox Code Playgroud)

一些代码,以及Fortran的方法调用

   #ifndef unix
      modlin_OM(pmt, abaque, don, cond, res, & iFlag) ;
   #else
modlin_om_(pmt, abaque, don, cond, res, & iFlag) ;
   #endif
Run Code Online (Sandbox Code Playgroud)

正如我之前所说,我通过删除这些行测试对C的调用并且内存没有增长:(我测试通过删除一行free(someVar)并且内存增长,因为在这种情况下没有完成.这就是为什么我的结论是我的C在Free/Malloc上没问题.

mco*_*ive 2

分析内存问题总是很复杂。根据我的经验,有两种方法:

1)你尝试重现。这假设您拥有源代码并了解根本原因。2) 您观察生产崩溃:频率、与其他事件的相关性等。

这可以帮助确定是否是内存泄漏(在业务负载下可能是高消耗......)

针对您的具体情况,我注意到以下几点:

  1. 代码的行为在不同的操作系统上可能有所不同。对于 Java 代码来说这种情况非常罕见(JVM bug)。它在本机代码中很常见(例如,忘记关闭 ZIP 会导致 Linux 上的内存泄漏,但在 Windows 上则不会......)

  2. 在 C 头文件 (*.h) 中:abaque、don 和 res 在 Windows 上是“float * *”,在 Unix 上是“float *”。这可能是您的 C 标头中的错误,或者意味着 C 实现不期望根据操作系统使用相同的参数类型(这对我来说很奇怪......)

在第二种情况下,您在 Windows 上编译 C 头文件(不是目标)的事实可以解释您没有生成正确的 JNI 存根(典型的交叉编译问题)...从这里我们可以做出许多假设,简单或者非常复杂...

祝你好运!