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上没问题.
分析内存问题总是很复杂。根据我的经验,有两种方法:
1)你尝试重现。这假设您拥有源代码并了解根本原因。2) 您观察生产崩溃:频率、与其他事件的相关性等。
这可以帮助确定是否是内存泄漏(在业务负载下可能是高消耗......)
针对您的具体情况,我注意到以下几点:
代码的行为在不同的操作系统上可能有所不同。对于 Java 代码来说这种情况非常罕见(JVM bug)。它在本机代码中很常见(例如,忘记关闭 ZIP 会导致 Linux 上的内存泄漏,但在 Windows 上则不会......)
在 C 头文件 (*.h) 中:abaque、don 和 res 在 Windows 上是“float * *”,在 Unix 上是“float *”。这可能是您的 C 标头中的错误,或者意味着 C 实现不期望根据操作系统使用相同的参数类型(这对我来说很奇怪......)
在第二种情况下,您在 Windows 上编译 C 头文件(不是目标)的事实可以解释您没有生成正确的 JNI 存根(典型的交叉编译问题)...从这里我们可以做出许多假设,简单或者非常复杂...
祝你好运!