成员顺序在Java中是否会像在C或C++中一样产生性能差异



在C和C++中,编译器不允许对结构的数据成员进行重新排序,因此如果不小心排序,最终会浪费空间。例如:

struct S {
int i;
void *p;
int i2;
};

在具有32位int和64位指针的平台上,将首先放置i,然后放置32位填充,以便p可以是64位–对齐。i2然后占据下一个字的一半,然后是另外32位的填充。生成的结构体有24个字节长,而如果首先声明p,则只有16个字节长。如果数组中有很多这样的结构,那么查找和删除填充有时是一个重要的优化,可以节省内存并减少缓存流失。

我很想知道Java是否有同样的功能。未装箱的类型(如intboolean)是否与引用大小相同或更小?如果它们较小,编译器是否允许对它们进行重新排序,以避免插入填充来对齐后续字段?最后,如果是的话,有编译器这样做吗?

我现在对此没有特别的优化需求,我只是想知道在选择声明字段的顺序时是否应该记住这一点,就像我在C.中所做的那样

int类型总是32位的,引用通常是32位的——即使在64位JVM中也是如此。

在不利的方面,Java在每个对象的开头都有一个8-12字节的头,并使用8字节对齐。顺便说一句,有些C++环境有一个16字节的对齐方式。

未装箱的类型(如int和boolean)是否与引用大小相同或更小?

对于boolean、byte、char和short,它们可以更小,但是对于long和double,基元可以比引用更大。

如果它们较小,编译器是否允许对它们进行重新排序,以避免插入填充来对齐后续字段?

JIT可以重新组织字段,甚至可以优化它们。

最后,如果是,有编译器会这样做吗?

javac编译几乎没有进行优化,查看字节码将不会为您提供运行时会发生什么的线索。JIT可以根据自己的选择优化对象中的字段。

我只是想知道,在选择声明字段的顺序时,是否应该记住这一点,就像我在C.中所做的那样

IMHO,您可以假设您在C中使用的几乎所有优化技巧在Java中都不再适用。在少数这样做的人中,他们可能并不完全相同。

您应该假设JIT会根据需要优化代码,并使用profiler来确定是否以及何时出现问题。只有这样,才能考虑出于性能原因更改代码。

在java中就存在这样的问题。编译器处理变量声明,程序员无法控制在内存中将它们分配到哪里

Java没有结构,只有类。Java中的类并不一定意味着该类也在C++后端。您甚至不知道JVM是否是用C/C++实现的。它可以用任何其他语言表达。

但是对于C++JVM,我认为它们试图进行优化。原始类型(它们不被称为unboxed),如int或boolean,通常映射到它们的原始对应类型(就我的JNI经验而言),但由于没有结构,它们不需要排列。

我几乎可以肯定重新划分类字段不会对内存消耗产生任何影响。只是因为它们不映射到structs。

正如其他人所指出的,在java中,您实际上无法控制这种级别的细节。然而,如果您真的需要对内存进行那么多控制,您可以通过在直接ByteBuffer中索引到byte[]甚至堆外来自己管理它。

最新更新