这个问题底部的代码有点长,但基本上是创建了一些对象并确定了它们在内存中的大小。我使用以下 JVM 参数执行代码(TLAB 是为了避免块内存分配并应该获得准确的内存使用数据):
-server -Xms2000m -Xmx2000m -verbose:gc -XX:-UseTLAB
我在 64 位 Hotspot JVM 上运行代码并获得以下输出:
Java HotSpot(TM) 64 位服务器 VM
对象:16 字节1 个整数的对象:16 个字节
2 个整数的
对象:24 个字节 3 个整数的对象:24 个字节具有 1 个 long 的对象:24 字节
具有 2 个 long 的对象:32 字节
具有 3 个 long 的对象:40 字节1 个引用的对象:16 字节
2 个引用的
对象:24 个字节 3 个引用的对象:24 个字节
我的结论是:
- 一个对象占用 12 个字节,对齐到 16 个字节。
- 一个 int 占用 4 个字节(1 个带有一个 int 的对象是 12 + 4 = 仍然是 16 个字节,有 2 个 int:12 + 8 = 20 对齐到 24 个字节)
- long 需要 8 个字节(1 个 long 对象是 12 + 8 = 20 个字节,对齐到 24 个字节)
但我很难理解为什么引用不使用long
s 那么多的空间。
由于引用在 64 位 JVM 上是 8 个字节,因此显而易见的结论是测量方法存在缺陷*。你能解释一下发生了什么以及可以做些什么来解决它?
*注:
- 测量期间不运行 GC。
- 使用 Netbeans 分析器会产生类似的结果。
public class TestMemoryReference {
private static final int SIZE = 100_000;
private static Runnable r;
private static Object o = new Object();
private static Object o1 = new Object();
private static Object o2 = new Object();
private static Object o3 = new Object();
public static class ObjectWith1Int { int i; }
public static class ObjectWith2Ints { int i, j; }
public static class ObjectWith3Ints { int i, j, k; }
public static class ObjectWith1Long { long i; }
public static class ObjectWith2Longs { long i, j; }
public static class ObjectWith3Longs { long i, j, k; }
public static class ObjectWith1Object { Object o = o1; }
public static class ObjectWith2Objects { Object o = o1; Object p = o2; }
public static class ObjectWith3Objects { Object o = o1; Object p = o2; Object q = o3; }
private static void test(Runnable r, String name, int numberOfObjects) {
long mem = Runtime.getRuntime().freeMemory();
r.run();
System.out.println(name + ":" + (mem - Runtime.getRuntime().freeMemory()) / numberOfObjects + " bytes ");
}
public static void main(String[] args) throws Exception {
System.out.println(System.getProperty("java.vm.name") + " ");
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object(); } };
test(r, "Object", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Int(); } };
test(r, "Object with 1 int", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Ints(); } };
test(r, "Object with 2 ints", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Ints(); } };
test(r, "Object with 3 ints", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Long(); } };
test(r, "Object with 1 long", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Longs(); } };
test(r, "Object with 2 longs", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Longs(); } };
test(r, "Object with 3 longs", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith1Object(); } };
test(r, "Object with 1 reference", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith2Objects(); } };
test(r, "Object with 2 references", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new ObjectWith3Objects(); } };
test(r, "Object with 3 references", SIZE);
}
}