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

Java中如何获取对象大小?使用Instrumentation代码遇空指针异常

解决Java中使用Instrumentation获取对象大小出现空指针异常的问题

你遇到的空指针异常,根源其实很明确:instrumentation这个静态变量根本没被初始化!

为啥会这样?因为premain方法是Java Agent的专属入口——只有当你把这个类作为Java Agent启动时,JVM才会在应用程序启动前调用它,传入合法的Instrumentation实例。但你直接运行C类的main方法时,premain完全不会被执行,instrumentation自然还是null,调用getObjectSize时可不就触发空指针了嘛。

下面给你两种靠谱的解决思路:

方法一:正确使用Java Agent(推荐,准确获取堆内存大小)

要让premain被调用,你需要把代码打包成Java Agent Jar,并在启动时指定这个Agent:

  1. 编写MANIFEST.MF文件:
    创建一个名为MANIFEST.MF的文件,内容如下:

    Premain-Class: ObjectSizeFetcher
    Can-Redefine-Classes: true
    

    这个文件告诉JVM,这个Jar是Java Agent,入口类是ObjectSizeFetcher。

  2. 打包成Jar:
    用jar命令把编译后的class文件和MANIFEST.MF打包:

    jar cvfm ObjectSizeFetcher.jar MANIFEST.MF ObjectSizeFetcher.class C.class
    
  3. 带着Agent运行程序:
    启动时通过-javaagent参数指定Agent Jar:

    java -javaagent:ObjectSizeFetcher.jar C
    

    这时候JVM会先执行premain初始化instrumentation,之后调用getObjectSize就不会有空指针了。

方法二:不用Agent的替代方案(适合快速估算)

如果不想折腾Java Agent,也可以用这些方法,但要注意它们的局限性:

1. 序列化估算大小

用序列化后的字节数来粗略估算对象大小,比如用Apache Commons Lang的工具类:

import org.apache.commons.lang3.SerializationUtils;

public class ObjectSizeFetcher {
    public static long getSerializedSize(Object o) {
        return SerializationUtils.serialize(o).length;
    }
}

⚠️ 注意:这个值是对象序列化后的字节数,和堆中真实大小有差异——序列化会额外添加格式信息,而且不会计算共享引用的对象大小,适合简单场景的粗略估算。

2. 使用Unsafe(不推荐,兼容性差)

通过sun.misc.Unsafe直接读取JVM内存布局来获取大小,但这是JVM内部API,不同版本/厂商的JVM可能不兼容:

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public class ObjectSizeFetcher {
    private static final Unsafe unsafe;

    static {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static long getObjectSize(Object o) {
        return unsafe.getAddress(unsafe.getInt(o, 4L) + 12L);
    }
}

⚠️ 警告:Java 9+对Unsafe的访问做了限制,而且不同JVM的对象内存布局可能不同,生产环境尽量别用这个方法。

总结一下:如果需要准确的堆内存大小,一定要用Java Agent的方式;如果只是粗略估算,序列化方法更稳妥;Unsafe方法只适合你对JVM内存布局非常熟悉的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:44:20