【问题标题】:Finding native memory allocations in a jna application using jemalloc使用 jemalloc 在 jna 应用程序中查找本机内存分配
【发布时间】:2021-12-06 09:34:29
【问题描述】:

我们有一个 Java 应用程序,它通过 JNA 调用用 C 编写的 .so 库,因此 Java 应用程序和 C 代码在同一个进程中运行。

我们发现了一个缓慢的内存泄漏,我们通过JVM堆监视器排除了JVM堆的原因,确认问题存在于JNA或C代码中。

我们发现jemalloc可以跟踪内存分配,所以我们安装了--prefix=/usr/local --enable-prof选项,并设置了LD_PRELOAD=/usr/local/lib/libjemalloc.soMALLOC_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 文件。此处显示的结果:memory leak profile

从图中,我们可以发现调用了很多关于java的方法。但是我们找不到任何关于 JNA 或 C 代码的信息。从图中我们发现了一个invoke分支,它只显示了16进制地址,所以不知道是JNA还是C。

我们使用perf-map-agent工具,做了导出符号映射,如下图:symbols mapping

但是当我们从 jeprof 结果中搜索符号映射结果的十六进制地址时,我们找不到关联的符号。

在这种情况下(通过 JNA 调用 C 库的 Java 应用程序)是否可以找到(C 函数名称或 JNA 代码)本机内存分配的位置,而不是 Java 堆内存?如果可以,怎么做?

【问题讨论】:

    标签: java c jna jemalloc


    【解决方案1】:

    大多数 JNA 内存分配是使用 Memory 类完成的。例如,此行将使用本机 malloc() 分配 1024 字节的内存。

    Memory buffer = new Memory(1024);
    

    许多其他 JNA 类,例如 Structure,在内部使用 Memory 缓冲区。 NativeLong 等其他类型也有适当大小的分配。

    所有这些本机内存分配最终都会作为 Java 垃圾收集过程的一部分被释放(finalize() 调用 dispose() 以释放内存)。

    但是,当分配是在本机代码内部完成时,如果不查看该源代码,就无法查看内存分配和释放的位置。但是,如果 Java/JNA 代码调用分配内存的本机函数,并且未能遵循 API 说明如何在完成后释放/释放该内存,则这是一个常见的泄漏源。

    底线:您确实必须查看源代码,并且对于在某处对内存进行操作的每个本机函数,找出您是否负责分配内存和传递缓冲区(Java/JNA 将负责释放它) 或者如果本机代码本身创建了它为您提供的缓冲区。如果是后一种情况,总会有另一种方法可以/应该使用来释放缓冲区。

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 1970-01-01
      • 2011-02-25
      • 2011-12-12
      • 2012-02-23
      • 2012-11-22
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      相关资源
      最近更新 更多