诚然,我不明白.假设您的内存中包含长度为1个字节的内存字.为什么不能在未对齐地址的单个内存访问中访问一个4字节长的变量(即不能被4整除),因为对齐地址就是这种情况?
有什么理由放弃std::allocator支持自定义解决方案?您是否遇到过正确性,性能,可扩展性等绝对必要的情况?有什么非常聪明的例子吗?
自定义分配器一直是我不太需要的标准库的一个功能.我只是想知道SO上的任何人是否可以提供一些令人信服的例子来证明他们的存在.
在Noda Time v2中,我们正在转向纳秒分辨率.这意味着我们不能再使用8字节整数来表示我们感兴趣的整个时间范围.这促使我调查Noda Time的(很多)结构的内存使用情况,这反过来又导致了我在CLR的对齐决定中发现一点点奇怪.
首先,我意识到这是一个实现决策,并且默认行为可能随时发生变化.我意识到我可以使用[StructLayout]和修改它[FieldOffset],但我想提出一个解决方案,如果可能的话不需要它.
我的核心方案是我有一个struct包含引用类型字段和另外两个值类型字段,其中这些字段是简单的包装器int.我希望,这将被表示为对64位的CLR(8用于参考和4每个其他)16个字节,但由于某些原因它使用24个字节.顺便说一下,我正在使用数组测量空间 - 我知道布局在不同的情况下可能会有所不同,但这感觉就像一个合理的起点.
这是一个展示问题的示例程序:
using System;
using System.Runtime.InteropServices;
#pragma warning disable 0169
struct Int32Wrapper
{
int x;
}
struct TwoInt32s
{
int x, y;
}
struct TwoInt32Wrappers
{
Int32Wrapper x, y;
}
struct RefAndTwoInt32s
{
string text;
int x, y;
}
struct RefAndTwoInt32Wrappers
{
string text;
Int32Wrapper x, y;
}
class Test
{
static void Main()
{
Console.WriteLine("Environment: CLR {0} …Run Code Online (Sandbox Code Playgroud) 可能重复:
为什么GCC不优化结构?
为什么C++不能使结构更紧凑?
请考虑以下32位x86计算机上的示例:
由于对齐约束,以下结构
struct s1 {
char a;
int b;
char c;
char d;
char e;
}
Run Code Online (Sandbox Code Playgroud)
如果成员被重新排序,则可以更有效地表示内存(12对8字节)
struct s2 {
int b;
char a;
char c;
char d;
char e;
}
Run Code Online (Sandbox Code Playgroud)
我知道C/C++编译器不允许这样做.我的问题是为什么语言是这样设计的.毕竟,我们最终可能会浪费大量的内存,而且struct_ref->b不会关心差异.
编辑:谢谢大家的非常有用的答案.您解释为什么由于语言的设计方式,重新排列不起作用.然而,它让我想到:如果重新排列是语言的一部分,这些论点是否仍然有效?让我们说有一些指定的重新排列规则,我们至少需要这个规则
我一个接一个地论证你的论点:
低级别的数据映射,"最惊喜的元素":只写你的结构以紧身款式自己(像@佩里的回答),并没有发生任何改变(要求1).如果由于一些奇怪的原因,你想要内部填充,你可以使用虚拟变量手动插入,和/或可能有关键字/指令.
编译器差异:要求3消除了这种担忧.实际上,从@David Heffernan的评论来看,我们今天似乎遇到了这个问题,因为不同的编译器填充不同?
优化:重新排序的重点是(内存)优化.我在这看到很多潜力.我们可能无法一起删除填充,但我没有看到重新排序如何以任何方式限制优化.
类型铸造:在我看来,这是最大的问题.不过,应该有办法解决这个问题.由于规则是用语言修复的,编译器能够弄清楚成员的重新排序方式,并做出相应的反应.如上所述,在您想要完全控制的情况下,始终可以防止重新排序.此外,要求2确保类型安全代码永远不会中断.
我认为这样的规则有意义的原因是因为我发现按结构内容而不是按类型对结构成员进行分组更为自然.当我有很多内部结构时,编译器也更容易选择最适合我的顺序.最佳布局甚至可能是我无法以类型安全的方式表达的布局.另一方面,它似乎使语言更复杂,这当然是一个缺点.
请注意,我不是在谈论改变语言 - 只有它可以(/应该)设计不同.
我知道我的问题是假设的,但我认为讨论提供了对机器和语言设计较低层次的更深入的了解.
我在这里很新,所以我不知道是否应该为此产生一个新问题.请告诉我是否是这种情况.
我有以下代码:
#include <stdio.h>
int
main(void)
{
float a[4] __attribute__((aligned(0x1000))) = {1.0, 2.0, 3.0, 4.0};
printf("%p %p %p %p\n", &a[0], &a[1], &a[2], &a[3]);
}
Run Code Online (Sandbox Code Playgroud)
我有以下输出:
0x7fffbfcd2da0 0x7fffbfcd2da4 0x7fffbfcd2da8 0x7fffbfcd2dac
Run Code Online (Sandbox Code Playgroud)
为什么地址a[0]不是多个0x1000?
到底__attribute__((aligned(x)))是什么?我误解了这个解释?
我正在使用gcc 4.1.2.
我正在研究单个生产者单个消费者环缓冲区实现.我有两个要求:
1)将单个堆分配的环形缓冲区实例与高速缓存行对齐.
2)将环形缓冲区内的字段与高速缓存行对齐(以防止错误共享).
我的班级看起来像:
#define CACHE_LINE_SIZE 64 // To be used later.
template<typename T, uint64_t num_events>
class RingBuffer { // This needs to be aligned to a cache line.
public:
....
private:
std::atomic<int64_t> publisher_sequence_ ;
int64_t cached_consumer_sequence_;
T* events_;
std::atomic<int64_t> consumer_sequence_; // This needs to be aligned to a cache line.
};
Run Code Online (Sandbox Code Playgroud)
让我首先解决第1点,即对齐单个堆分配的类实例.有几种方法:
1)使用c ++ 11 alignas(..)说明符:
template<typename T, uint64_t num_events>
class alignas(CACHE_LINE_SIZE) RingBuffer {
public:
....
private:
// All the private fields.
};
Run Code Online (Sandbox Code Playgroud)
2)使用 …
我刚刚看到 C++ 23计划弃用std::aligned_storageandstd::aligned_storage_t以及std::aligned_union。std::aligned_union_t
据我所知,在对齐存储中放置新对象并不是特别constexpr友好,但这似乎不是完全丢弃该类型的好理由。这让我假设使用std::aligned_storage和朋友还存在一些我不知道的其他基本问题。那会是什么?
是否有建议替代这些类型?
我现在正在使用共享内存.
我无法理解alignof和alignas.
cppreference不清楚:alignof返回"对齐"但什么是"对齐"?要为要对齐的下一个块添加的字节数?填充尺寸?堆栈溢出 /博客条目也不清楚.
有人能解释清楚alignof和alignas?
为了防止错误共享,我想将数组的每个元素对齐到缓存行.所以首先我需要知道缓存行的大小,因此我为每个元素分配了大量的字节.其次,我希望数组的开始与高速缓存行对齐.
我使用的是Linux和8核x86平台.首先,我如何找到缓存行大小.其次,如何与C中的缓存行对齐.我正在使用gcc编译器.
因此,假设高速缓存行大小为64,结构将遵循.
element[0] occupies bytes 0-63
element[1] occupies bytes 64-127
element[2] occupies bytes 128-191
Run Code Online (Sandbox Code Playgroud)
等等,当然假设0-63与高速缓存行对齐.
[不是结构填充和包装的重复。这个问题是关于填充的方式和时间。这是关于如何处理它的信息。]
我刚刚意识到C ++中的对齐会浪费多少内存。考虑以下简单示例:
struct X
{
int a;
double b;
int c;
};
int main()
{
cout << "sizeof(int) = " << sizeof(int) << '\n';
cout << "sizeof(double) = " << sizeof(double) << '\n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << '\n';
cout << "but sizeof(X) = " << sizeof(X) << '\n';
}
Run Code Online (Sandbox Code Playgroud)
使用g ++时,程序将提供以下输出:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but …Run Code Online (Sandbox Code Playgroud) c++ optimization memory-alignment memory-layout struct-member-alignment