Java 类的内存对齐
Posted
技术标签:
【中文标题】Java 类的内存对齐【英文标题】:Memory alignment of Java classes 【发布时间】: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 字节的倍数对齐。
【问题讨论】:
【参考方案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。我修正了我的答案。以上是关于Java 类的内存对齐的主要内容,如果未能解决你的问题,请参考以下文章