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

Java Instrumentation接口实现报错及对象内存估算问题求助

Java对象内存估算相关问题

我正在为一个项目估算部分对象的内存,打算用Instrumentation接口的getObjectSize()方法。参考资料后创建Instrumentation Agent,但制作带自定义清单文件的Agent JAR时,出现错误:java.io.FileNotFoundException: META-INF/MANIFEST.MF (No such file or directory)。

执行的完整命令及错误如下:

user@users-MacBook-Pro objectTesting % jar -cfm Sizeof.jar META-INF/MANIFEST.MF Sizeof.class
java.io.FileNotFoundException: META-INF/MANIFEST.MF (No such file or directory)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:219)
at java.base/java.io.FileInputStream.(FileInputStream.java:158)
at java.base/java.io.FileInputStream.(FileInputStream.java:112)
at jdk.jartool/sun.tools.jar.Main.run(Main.java:278)
at jdk.jartool/sun.tools.jar.Main.main(Main.j

我已经单独创建项目文件夹尝试让Instrumentation接口正常工作,最初以为是manifest文件和META-INF文件夹位置错误,但调整多次后仍报错。


解决方案

1. 修复JAR打包的文件找不到错误

这个错误的核心是执行jar命令时,当前目录下不存在META-INF/MANIFEST.MF文件,或者路径写错了。按以下步骤解决:

  • 先在执行命令的objectTesting目录下,手动创建META-INF文件夹,在里面新建MANIFEST.MF文件,内容必须包含Agent的入口配置,比如:
    Premain-Class: Sizeof
    Can-Redefine-Classes: true
    
    注意:文件最后必须保留空行,否则jar命令会解析失败。
  • 确认文件路径正确后再执行打包命令,如果Sizeof.class在当前目录,命令直接使用即可;如果类文件在子目录(比如target/classes),要补全路径:
    jar -cfm Sizeof.jar META-INF/MANIFEST.MF ./Sizeof.class
    

2. 将Instrumentation Agent应用到其他项目

Agent打包成JAR后,有两种方式在其他项目中使用:

  • 启动时加载:启动目标Java程序时,添加JVM参数指定Agent JAR的绝对路径:
    # 针对可执行JAR
    java -javaagent:/绝对路径/Sizeof.jar -jar 你的项目.jar
    # 针对普通主类
    java -javaagent:/绝对路径/Sizeof.jar com.你的包名.MainClass
    
  • 动态加载:如果目标程序已经在运行,可以通过Attach API动态注入Agent,需要引入com.sun.tools.attach:attach-api依赖,示例代码:
    import com.sun.tools.attach.AttachNotSupportedException;
    import com.sun.tools.attach.VirtualMachine;
    import java.io.IOException;
    
    public class AttachAgent {
        public static void main(String[] args) throws IOException, AttachNotSupportedException {
            // 替换为目标进程的PID
            VirtualMachine vm = VirtualMachine.attach("12345");
            vm.loadAgent("/绝对路径/Sizeof.jar");
            vm.detach();
        }
    }
    

3. Java中其他估算对象内存消耗的方法

除了Instrumentation,还有这些常用方法:

  • Runtime类差值法:通过创建对象前后的内存差值估算,误差较大(受GC、其他对象影响):
    Runtime runtime = Runtime.getRuntime();
    long before = runtime.totalMemory() - runtime.freeMemory();
    Object obj = new YourObject();
    long after = runtime.totalMemory() - runtime.freeMemory();
    System.out.println("对象大小:" + (after - before) + "字节");
    
  • 序列化字节法:用工具将对象序列化为字节数组,通过数组长度估算,仅包含可序列化部分,忽略引用:
    byte[] bytes = org.apache.commons.lang3.SerializationUtils.serialize(obj);
    System.out.println("对象大小:" + bytes.length + "字节");
    
  • JOL工具库:直接查看对象内存布局和精确大小,精度很高:
    System.out.println(org.openjdk.jol.info.GraphLayout.parseInstance(obj).toPrintable());
    
  • 手动计算:根据JVM内存规则(对象头、实例数据、对齐填充)手动计算,比如64位JVM开启压缩指针时,普通对象头占16字节,加上各字段大小后对齐到8字节倍数。

内容的提问来源于stack exchange,提问作者wdk23

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 03:16:09