文章目录
1. 使用 java.lang.instrument.Instrumentation
(精确计算)
这是最准确的方法,但需要通过Java Agent来实现:
- 创建一个Java Agent类:
import java.lang.instrument.Instrumentation;
public class ObjectSizeAgent {
private static volatile Instrumentation globalInstrumentation;
public static void premain(String agentArgs, Instrumentation inst) {
globalInstrumentation = inst;
}
public static long getObjectSize(Object obj) {
if (globalInstrumentation == null) {
throw new IllegalStateException("Instrumentation not initialized");
}
return globalInstrumentation.getObjectSize(obj);
}
}
-
配置
MANIFEST.MF
:- 在
MANIFEST.MF
中添加:Premain-Class: com.example.ObjectSizeAgent
- 在
-
打包为JAR并运行:
java -javaagent:objectsizeagent.jar YourMainClass
-
在代码中使用:
public class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
long size = ObjectSizeAgent.getObjectSize(obj);
System.out.println("Object size: " + size + " bytes");
}
}
2. 使用第三方库(简化实现)
2.1. jol-core
(Java Object Layout)
由OpenJDK团队开发,可直接计算对象大小:
import org.openjdk.jol.info.ClassLayout;
public class ObjectSizeCalculator {
public static void main(String[] args) {
MyClass obj = new MyClass();
System.out.println(ClassLayout.parseInstance(obj).toPrintable());
}
}
依赖(Maven):
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.16</version>
</dependency>
2.2. Apache Commons Lang
SerializationUtils.serialize()
可估算序列化后的大小:
import org.apache.commons.lang3.SerializationUtils;
public class ObjectSizeEstimator {
public static void main(String[] args) {
MyClass obj = new MyClass();
byte[] bytes = SerializationUtils.serialize(obj);
System.out.println("Serialized size: " + bytes.length + " bytes");
}
}
3. 手动估算(基于JVM规范)
对象在内存中的结构通常包括:
- 对象头(Object Header):
- Mark Word(通常8字节)
- 类型指针(4或8字节,取决于是否开启指针压缩)
- 实例数据(Instance Data):字段的实际值
- 对齐填充(Padding):按8字节对齐
示例计算:
class MyClass {
int a; // 4字节
long b; // 8字节
String c; // 引用类型:4或8字节
}
- 总大小估算:
- 对象头:12字节(8+4,假设开启指针压缩)
- 实例数据:4(
a
) + 8(b
) + 4(c
) = 16字节 - 对齐填充:4字节(总大小需为8的倍数)
- 总计:12 + 16 + 4 = 32字节
4. 注意事项
-
指针压缩(Compressed OOPs):
- 64位JVM默认开启,对象引用占4字节(否则占8字节)。
- 通过
-XX:+UseCompressedOops
控制。
-
数组和集合:
- 数组对象包含额外的长度字段。
- 集合类(如
ArrayList
)需计算内部数组的大小。
-
静态字段:
- 静态字段不属于对象实例,不计入对象大小。
5. 工具推荐
- JProfiler:可视化工具,直接查看对象大小。
- YourKit:支持内存分析和对象大小统计。
- Eclipse Memory Analyzer (MAT):分析堆转储文件。
总结
- 精确计算:使用
Instrumentation
或jol-core
。 - 快速估算:手动计算对象头、字段和对齐填充。
- 复杂场景:借助专业工具分析堆内存。
一般场景下推荐 方案2