类 的 C++ 布局新对齐(在 SAMD21 微控制器上)

C++ placement new alignment of classes (on a SAMD21 microcontroller)

我正在开发一个在 SAMD21 微控制器上 运行 的应用程序。对于那些不熟悉 SAMD21 的人,它包含一个 ARM Cortex-M0+ 处理器。我使用的具体型号有 32 kB 的 RAM。我的应用程序 运行 达到了 32 kB 的限制,因此我一直致力于优化内存使用代码。

我一直致力于的一项优化是减少堆碎片。比如我可能有这样一个场景:

A *my_obj = new A();
B *my_second_obj = new B();
delete A;
C *my_third_obj = new C();

在上面的示例中,在实例化 my_third_obj 时,内存分配器可能会尝试将其放置在最初由 my_obj 使用的空位置。但是,如果 my_third_obj 不适合那个位置,那么内存分配器将简单地在堆顶部分配更多 space 并移动堆指针。这将在 my_obj 所在的位置留下一个“洞”(稍后可能会被其他对象填充),但这会产生堆碎片。

在我的特定应用程序中,我确定我在任何时间点都只需要 classes A、B 或 C 的一个活动实例。因此,我正在考虑创建一个内存块来保存任何这些 classes 的当前实例,并简单地使内存块与最大的 class 一样大,以便它可以容纳class 中的任何一个。这将减少堆碎片,因为内存中总会有一个特定的位置,我将在其中分配这些特定的 classes.

这是我的想法的一个简单示例:

uint32_t max_size = sizeof(A);
max_size = (sizeof(B) > max_size) ? sizeof(B) : max_size;
max_size = (sizeof(C) > max_size) ? sizeof(C) : max_size;
uint8_t *buffer = new uint8_t[max_size];

//Some time later in the program...
C *my_obj = new(buffer) C();

//Some time later in the program...
my_obj->~C();
my_obj = NULL;
memset(buffer, 0, sizeof(max_size));
B *my_other_obj = new(buffer) B();

我在以前编写的代码中从未真正使用过 placement new,但我认为它对我目前的情况很有用。我的主要问题是:鉴于我已经列出的示例,我是否需要以任何方式更改代码来处理对齐问题? 类A、B、C的成员变量不同,大小也不同。这段代码是否“有效”,或者我是否需要做任何特殊的事情来处理内存对齐?

谢谢!

从 malloc 获得的缓冲区保证对任何基本类型都正确对齐,但我不确定从 new 获得的指针是否是,所以我更喜欢:

uint8_t *buffer = malloc(max_size);   // delete it later with free

但您甚至可以通过使用 alignas:

构建自定义缓冲区来摆脱任何动态分配
// only required for C++11, starting from C++14, std::max is constepr
constexpr size_t max3(size_t i, size_t j, size_t k) {
    uint32_t max_size = i;
    max_size = (i > j) ? i : j;
    max_size = (k > max_size) ? k : max_size;
    return max_size;
}

// declare a custom struct with required size and alignment
struct alignas(max3(alignof(A), alignof(B), alignof(C))) Buffer {
    char buffer[max3(alignof(A), alignof(B), alignof(C))];
};

// build a statically allocated buffer of correct size and alignment
Buffer buffer;

从那时起,您可以安全地在 buffer 中构造一个对象,当然在重新使用内存之前明确地销毁它。

do I need to alter the code in any way to handle alignment issues?

是的。

do I need to do anything special to handle memory alignment?

是的。

uint8_t 在概念上表示一个 8 位的无符号整数。用charunsigned char表示1个字节。

无论如何,请使用 operator new 大小和对齐方式:

auto maxsize = max_of_3(sizeof(A), sizeof(B), sizeof(C)),
auto neededalign = std::align_val_t(max_of_3(alignof(A), alignof(B), alignof(C));
void *buffer = operator new(maxsize, neededalign);

或静态:

std::aligned_storage<
    max_of_3(sizeof(A), sizeof(B), sizeof(C)),
    max_of_3(alignof(A), alignof(B), alignof(C))> buffer;
A *stuff = new(buffer.data) A;