我们有一个Java应用程序,它通过JNA调用用C编写的.so库,因此Java应用程序和C代码运行在同一个过程中。
我们发现了一个缓慢的内存泄漏,并且通过JVM堆监视器将JVM堆排除在外,确认JNA或C代码中存在这个问题。
我们发现jemalloc可以跟踪内存分配,所以我们用--prefix=/usr/local --enable-prof
选项安装它,并设置LD_PRELOAD=/usr/local/lib/libjemalloc.so
和MALLOC_CONF=prof_leak:true,lg_prof_sample:17,prof_final:true,prof_prefix:/home/admin/prof_dump/jeprof
环境。它生成一个转储文件,然后使用jeprof工具并使用jeprof --show_bytes --pdf \ jeprof.* \ > ./wdmp-profiling.pdf
将转储文件转换为pdf文件。这里显示的结果是:内存泄漏剖面
从图中,我们可以找到许多关于java调用的方法。但是我们找不到关于JNA或C代码的任何信息。从图中我们找到了一个调用分支,它只显示十六进制地址,所以我们不确定它是与JNA还是C有关。
我们使用了perf-地图代理工具并进行了导出符号映射,如下所示:符号映射
但是,当我们在符号映射结果中从jeprof中搜索十六进制地址时,我们无法找到相关的符号。
在这种情况下(通过JNA调用C库的Java应用程序)是否能够找到(C函数名或JNA代码)本地内存的分配位置,而不是java堆内存?如果可能的话,怎么做?
发布于 2021-12-07 18:44:11
大多数JNA内存分配是使用Memory
类完成的。例如,这一行将使用本机malloc()
分配1024字节的内存。
Memory buffer = new Memory(1024);
许多其他的JNA类,如Structure
,在内部使用Memory
缓冲区。其他类型(如NativeLong
)也有适当的大小分配。
所有这些本机内存分配最终都是作为Java垃圾收集过程的一部分释放的(finalize()
调用dispose()
来释放内存)。
但是,当在内部对本机代码进行分配时,除非查看该源,否则无法查看内存分配和释放的位置。但是,如果Java/JNA代码调用分配内存的本机函数,并且无法按照API说明来释放/释放内存,这是一个常见的泄漏源。
底线:您确实需要查看源代码以及在内存中操作的每个本机函数,找出您是否负责分配内存和传递缓冲区(Java/JNA将负责释放它),或者本机代码本身是否创建了它提供的缓冲区。如果是后一种情况,则始终会有另一种方法可以/应该用来释放缓冲区。
https://stackoverflow.com/questions/70243376
复制相似问题