【问题标题】:Memory alignment of Java classesJava 类的内存对齐
【发布时间】:2017-11-12 02:41:07
【问题描述】:

假设我在一个 64 位机器上用gcc 编译一个 C 程序。我假设 sizeof(int) 是 8 个字节,sizeof(char) 是 1 个字节。

由于内存对齐,下面的struct:

struct example{
    int a;
    char c;
}

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

我想知道以下类在 Java 8 中会有多大:

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

我基本上不确定我们是否会以 8 字节或 4 字节的倍数对齐。

【问题讨论】:

    标签: java memory-alignment


    【解决方案1】:

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

    # 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 个字节。

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

    【讨论】:

    • 啊,对齐信息就在那里。太好了,谢谢!
    • 包含使用的命令会很有用。我可以按照链接的文档使其适用于 JDK 类,但尝试为像 Node 这样的简单 .class 文件重现此文件我得到ClassNotFoundException。困惑。
    • @LukeUsherwood 你看到this了吗?我用的是 Java 8。
    • 我浏览了一些示例,但印象中您可以按照链接 wiki 的“用作命令行工具”部分中的示例在命令行上执行此操作。 (我找不到像-cp 这样的标志,所以我想也许工作目录设置得当......)所以你编写了代码并以编程方式打印了这些数据,我接受了吗?
    • 我使用java -cp "jol-cli-0.9-full.jar:." org.openjdk.jol.Main internals package.ClassUnderTest 创建了可比较的表。我对结果有点困惑:看到上面它是在 64 位机器/jvm 上执行的。类似乎与字长(8 字节)对齐。基元根本没有对齐。并且引用对齐到半字(4 个字节)。真的是这样吗?
    【解决方案2】:

    ZhekaKozlov 的回答不正确。

    至少在 JDK8 上的 Hotspot JVM 中,无论是 32 位 JVM 还是 64 位,对齐方式默认为 8 个字节。

    (对不起,我没有足够的代表发表评论,所以我必须发布一个新答案)

    在Oracle jdk-8u251 x86版本上试过,

    您可以尝试使用选项XX:ObjectAlignmentInBytes=4 启动您的(热点)JVM,它会失败并出现错误:

    ObjectAlignmentInBytes=4 必须大于或等于 8

    有趣的旁注,如果你把它设置为9,它也会抱怨这个数字必须是2的幂。

    同样在上面的 JVM 上运行这段代码 sn-p 没有任何明确的 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 规范中定义,因此它可能因实现而异。

    【讨论】:

    • 你是绝对正确的。在 32 位 JVM 上,对象对齐也永远不会少于 8 个字节。这解释了here。我修正了我的答案。
    猜你喜欢
    • 2013-02-02
    • 1970-01-01
    • 2019-11-20
    • 2010-12-29
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    相关资源
    最近更新 更多