Java类的内存对齐

7
假设我在一台64位机器上用gcc编译C程序。我假设sizeof(int)为8字节,sizeof(char)为1字节。
由于内存对齐的原因,以下结构体:
struct example{
    int a;
    char c;
}

实际上,以下这个类的大小不是9个字节,而是16个字节(等于两个 sizeof(int)),因此它的开始和结束地址都可以是字长的倍数(这里假设字长为8个字节)。

我想知道在Java 8中以下类的大小是多少:

class Node {
    int val;
    Node left, right;
    boolean flag;
 }

我不确定我们是否需要按8或4字节的倍数对齐。

2个回答

17

你可以使用jol来了解对象的准确布局。 这是在Oracle JDK 1.8.0_121 64位上针对您的Node类的程序输出:

# Running 64-bit HotSpot VM.
# Using compressed oop with 3-bit shift.
# Using compressed klass with 3-bit shift.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

org.example.Node object internals:
OFFSET  SIZE    TYPE DESCRIPTION                    VALUE
     0     4         (object header)                01 00 00 00 (00000001 00000000 00000000 00000000) (1)
     4     4         (object header)                00 00 00 00 (00000000 00000000 00000000 00000000) (0)
     8     4         (object header)                70 22 01 f8 (01110000 00100010 00000001 11111000) (-134143376)
    12     4     int Node.val                       0
    16     1 boolean Node.flag                      false
    17     3         (alignment/padding gap)        N/A
    20     4    Node Node.left                      null
    24     4    Node Node.right                     null
    28     4         (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes total

所以,对齐方式为8字节。

注意,这是特定于平台的。您不应过多依赖此信息。


啊,对齐信息就在那里。太好了,谢谢! - Jason
1
包含使用的命令会很有用。我可以按照链接文档来使其适用于JDK类,但是尝试将其复制到像Node这样的简单.class文件时,我会遇到“ClassNotFoundException”。感到困惑。 - Luke Usherwood
@LukeUsherwood 你看到这个了吗?我使用的是Java 8。 - ZhekaKozlov
我浏览了一些例子,但是根据链接维基中“用作命令行工具”部分的示例,我有印象可以在命令行上完成它。(我找不到像“-cp”这样的标志,所以我想也许如果工作目录设置得当...)那么你是编写代码并以编程方式打印这些数据的,对吗? - Luke Usherwood
1
我使用 java -cp "jol-cli-0.9-full.jar:." org.openjdk.jol.Main internals package.ClassUnderTest 创建了可比较的表格。但是,结果让我有些困惑:上面显示它在64位机器/jvm上执行。类似乎对齐到字大小(8个字节)。原始类型根本没有对齐。而引用则对齐到半字(4个字节)。这是真的吗? - steve

4
ZhekaKozlov的回答是不正确的。 在至少JDK8上的Hotspot JVM中,默认情况下对齐方式为8字节,无论是32位JVM还是64位。 (抱歉我没有足够的声望来评论,所以我必须发布一个新答案) 在Oracle jdk-8u251 x86版本上尝试, 您可以尝试使用选项XX:ObjectAlignmentInBytes = 4启动(Hotspot)JVM,它将失败并显示错误: 对象对齐方式必须大于或等于8 有趣的副作用是,如果将其设置为9,则还会抱怨该数字必须是2的幂。 还要在上述JVM上运行此代码片段,而不需要设置任何显式VM选项,使用jol
System.out.println(VM.current().details());

它将打印

# Running 32-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 4, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

请注意,JVM规范中未定义对齐大小,因此可能会因实现而异。

1
你是完全正确的。32位JVM上对象对齐方式也不少于8个字节。这在这里有解释。我已经修正了我的回答。 - ZhekaKozlov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接