Java 获取 List 对象内存大小
在 Java 开发中,我们经常需要统计和管理对象的内存使用情况。对于 List 对象来说,如何获取其占用的内存大小是一个常见的需求。本文将介绍几种在 Java 中获取 List 对象内存大小的方法,并提供相应的代码示例。
方法一:使用 Instrumentation
Java 提供了一个 Instrumentation 接口,可用于测量对象的大小。通过该接口,我们可以获取 List 对象占用的内存大小。
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.List;
public class MemoryUtil {
private static Instrumentation instrumentation;
public static void premain(String args, Instrumentation inst) {
instrumentation = inst;
}
public static long getObjectSize(Object obj) {
if (instrumentation != null) {
return instrumentation.getObjectSize(obj);
}
throw new IllegalStateException("Instrumentation is not initialized");
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
long size = getObjectSize(list);
System.out.println("List object size: " + size + " bytes");
}
}
在上述代码中,我们通过 Instrumentation.getObjectSize()
方法获取 List 对象的大小,并输出到控制台。
要使用 Instrumentation,需要在 JVM 启动时添加 -javaagent
参数,并指定一个代理类。在代理类中,我们可以通过实现 premain
方法来初始化 Instrumentation 对象。在 getObjectSize
方法中,我们通过检查 Instrumentation 对象是否已初始化来确保获取对象大小的正确性。
方法二:使用 Object 测量方法
除了使用 Instrumentation 接口外,我们还可以通过创建一个临时的 Object 对象,然后计算其大小差值来估算 List 对象的大小。这种方法不需要使用 Instrumentation 接口,但可能不够准确。
import java.util.ArrayList;
import java.util.List;
public class MemoryUtil {
public static long getObjectSize(Object obj) {
long baseSize = getBaseSize();
long referenceSize = getReferenceSize();
long objectSize = baseSize + referenceSize * ((List<?>) obj).size();
return align(objectSize);
}
private static long getBaseSize() {
return align(12); // 对象头部分配 12 个字节
}
private static long getReferenceSize() {
return align(4); // 指针大小为 4 个字节
}
private static long align(long size) {
return (size + 7) / 8 * 8; // 对齐到 8 的倍数
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
long size = getObjectSize(list);
System.out.println("List object size: " + size + " bytes");
}
}
在上述代码中,我们估算 List 对象的大小,首先需要计算一个对象的基本大小(baseSize
)和一个引用的大小(referenceSize
)。基本大小是对象头部分配的字节数,引用大小是指针的大小。
然后,我们将基本大小和引用大小乘以 List 对象的元素个数,得到总的对象大小。最后,我们对对象大小进行对齐操作,以满足内存对齐的要求。
方法三:使用第三方库
除了上述两种方法,还可以使用一些第三方库来获取 List 对象的内存大小。例如,Apache Commons Lang3 库提供了 SizeOf
类,可以用于测量对象的大小。
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class MemoryUtil {
public static long getObjectSize(Object obj) throws Exception {
Method sizeMethod = MethodUtils.getAccessibleMethod(obj.getClass(), "size");
int size = (int) sizeMethod.invoke(obj);
Field elementDataField = FieldUtils.getDeclaredField(obj.getClass(), "elementData", true);
Object[] elementData = (Object[]) elementDataField.get(obj);
long objectSize = 12 + 4 + size * 4 + elementData.length * 4;
return align(objectSize);
}
private static long align(long size) {
return (size + 7) / 8 *