0

我正在开发一个在 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不适合该位置,则内存分配器将简单地在堆顶部分配更多空间并移动堆指针。这会在原来的位置留下一个“洞” my_obj(稍后可能会被其他对象填充),但这会产生堆碎片。

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

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

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 都有不同的成员变量和不同的大小。这段代码会“工作”,还是我需要做一些特别的事情来处理内存对齐?

谢谢!

4

2 回答 2

1

保证从 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,当然在重新使用内存之前明确地销毁它。

于 2021-09-23T10:19:41.370 回答
1

我是否需要以任何方式更改代码来处理对齐问题?

是的。

我需要做一些特别的事情来处理内存对齐吗?

是的。

uint8_t概念上表示一个 8 位的无符号整数。使用charorunsigned 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;
于 2021-09-23T10:38:39.550 回答