我们的标题在我们的大多数结构(用于网络和文件I/O)使用#pragma pack(1)
。我知道它会将结构的对齐从8个字节的默认值更改为1个字节的对齐。使用杂注包(1)时是否存在性能问题?
假设一切都在32位Linux(也许是太的Windows)上运行,有没有即来源于此包装对准任何性能影响?
我不关心移植的库,但多与文件和网络I/O不同的#pragma pack和性能问题的兼容性。
我们的标题在我们的大多数结构(用于网络和文件I/O)使用#pragma pack(1)
。我知道它会将结构的对齐从8个字节的默认值更改为1个字节的对齐。使用杂注包(1)时是否存在性能问题?
假设一切都在32位Linux(也许是太的Windows)上运行,有没有即来源于此包装对准任何性能影响?
我不关心移植的库,但多与文件和网络I/O不同的#pragma pack和性能问题的兼容性。
当字对齐的内存地址发生时,内存访问速度最快。最简单的例子是下面的结构(其@Didier也使用):
struct sample {
char a;
int b;
};
默认情况下,GCC插入填充,所以是在偏移0,并且b在偏移4(字对齐)。没有填充,b不是字对齐的,并且访问速度较慢。
慢多少?
处理器需要两个存储器 访问使未对齐的内存访问;对齐的访问只需要一个内存访问。跨越4字节边界的字或双字操作数或跨越8字节边界的双字操作数被认为是未对齐的,并且 需要两个单独的存储器总线周期来访问。与大多数性能问题一样,您必须对您的应用程序进行基准测试,以查看实际中存在多少问题。
关于可移植性:我假设你正在使用#pragma pack(1)
这样就可以发送跨线及到磁盘结构,无需担心不同的编译器或平台包装结构不同。这是有效的,但是,有几个问题需要记住:
+1表示出色的答案,并指出某些非x86体系结构实际上*需要*针对某些数据类型进行适当对齐。 –
Endinaness实际上并没有处理,但它是“OK”,因为我们的整个后台都是Linux驱动的。我会实际运行一个基准测试,并且可能会在这里回报。谢谢你的答案。 – Nicolas
当你声明一个结构时,大多数编译器会在成员之间插入填充字节,以确保它们与内存中的适当地址对齐(通常填充字节是该类型大小的倍数)。这使编译器能够对这些成员进行优化访问。
#pragma pack(1)
指示编译器包与特定对准结构的成员。这里的1
告诉编译器不要在成员之间插入任何填充。
所以是有一定的性能损失,因为你强制编译器做一些超出它自然会为性能optimization.Also做,一些平台的需求,该物体在特定边界和使用unalighed对齐结构可能会给你分段错误。
理想的情况下,最好是避免更改默认的自然对齐规则。但是,如果根本无法避免'包装'指令(就像你的情况那样),那么在定义需要紧密包装的结构之后,必须恢复原包装方案。
对于如:
//push current alignment rules to internal stack and force 1-byte alignment boundary
#pragma pack(push,1)
/* definition of structures that require tight packing go in here */
//restore original alignment rules from stack
#pragma pack(pop)
或者更好,使用gcc的本地['aligned'属性](http://gcc.gnu.org/onlinedocs/gcc-3.2.3/gcc/Type-Attributes.html)来标记当前结构。 –
是的。绝对有。
举例来说,如果你定义一个结构:
struct dumb {
char c;
int i;
};
那么每当你访问我时,CPU减慢成员,因为32位值我不是本地人,对齐方式访问。为了简单起见,假设CPU必须从存储器获得3个字节,然后从下一个位置获得另外1个字节,以将值从存储器传输到CPU寄存器。
从技术上讲,是的,它会影响性能,但仅限于内部处理。如果您需要为网络/文件IO打包的结构,则打包的需求和内部处理之间会有一个平衡。通过内部处理,我的意思是,你在IO之间的数据上做的工作。如果你做的处理很少,你不会在性能方面损失太多。否则,您可能希望在正确对齐的结构上进行内部处理,并且只在执行IO时“打包”结果。或者您可以切换为仅使用默认的对齐结构,但您需要确保每个人都以相同的方式对齐它们(网络和文件客户端)。
某些机器码指令可以在32位或64位(甚至更多)上运行,但希望数据在内存地址上对齐。如果不是,他们必须在内存上执行多个读/写操作才能执行任务。 该性能如何影响很大程度上取决于您对数据所做的操作。如果您构建大型结构数组并对其执行大量计算,则可能会变得很大。但是,如果您只是将数据存储一次,然后再将其转换为字节流,那么它可能几乎不可知。
我甚至不知道GCC支持'#pragma pack'。不是我现在要使用它。 –
@larsmans是的,由于Windows:http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas。html – Nicolas