You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux环境下Java运行时获取已加载本地库内存占用的方法

问题描述

我在Linux系统上通过JVM运行Java应用,希望获取应用初始化阶段加载的特定本地库Tested_Lib的内存消耗。当前加载该库的代码如下:

public class Test 
{
     static
     { 
        System.loadLibrary("Tested_Lib");
     }

     public int register () { ......}
     public int unregister () { ......}
}

我有两个疑问:

  1. 这种加载方式是否会将该库的全部大小加载至JVM地址空间?
  2. 如何在运行时测量Tested_Lib的内存占用?

我曾尝试以下方法,但得到的结果与预期的库大小相差甚远:

System.gc();
        usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
 
        System.loadLibrary("Tested_Lib");

        usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
        libSizeInRam = (usedMemoryAfter - usedMemoryBefore)/KILOBYTE;  
解答

疑问1:加载方式是否会把库的全部大小加载到JVM地址空间?

不会。Linux系统采用内存分页和**按需加载(懒加载)**机制处理动态库:

  • 动态库的代码段(.text)会被多个进程共享,且只有当实际执行到对应代码页时才会加载到物理内存;
  • 数据段(.data、.bss)属于进程私有,加载时仅分配虚拟内存空间,物理内存同样是在实际写入时才真正分配;
  • System.loadLibrary底层调用Linux的dlopen接口,它只会把库映射到进程的虚拟地址空间,不会立刻将整个库的所有内容加载到物理内存。

疑问2:如何运行时测量Tested_Lib的内存占用?

你之前用JVM堆内存统计的方法无效,因为totalMemory()和freeMemory()仅能统计JVM堆内存的使用情况,而本地库的内存属于进程堆外内存,不在JVM堆的统计范围内。推荐以下几种Linux下的可行方法:

方法1:使用pmap工具

直接查看进程的内存映射,定位Tested_Lib的内存占用:

  1. 获取Java进程PID:执行jps或ps aux | grep java;
  2. 执行pmap -x <PID>,在输出中找到Tested_Lib对应的行:
    • RSS列是该库实际占用的物理内存大小;
    • SIZE列是该库映射的虚拟地址空间大小。

方法2:解析/proc/<PID>/smaps文件

这是更精确的统计方式,/proc文件系统提供了进程的详细内存映射信息:

  1. 执行cat /proc/<PID>/smaps | grep -A 10 "Tested_Lib",输出包含该库各段的内存统计:
    • Rss:物理内存占用;
    • Pss:考虑共享后的实际占用(代码段为多进程共享,Pss会按共享进程数分摊);
    • Private_Dirty:进程私有的脏内存(比如修改过的数据段)。

方法3:在代码中调用Linux系统API

如果需要在Java程序内获取,可以通过JNI调用Linux系统函数:

  • 调用dlopen打开库后,使用dlinfo获取库的加载地址和大小;
  • 结合/proc/self/smaps解析对应地址范围的内存占用。

内容的提问来源于stack exchange,提问作者Islam Gamal Abd El-Naser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:08:16