继续昨天的问题:std::priority_queue 预分配内存 内存错误
我正在开展一个确定性实时项目,该项目每次迭代的执行周期为几百微秒。
我面临的问题是,std::queue 和 std::priority_queue 上的推送操作随机花费大量时间。推送操作通常需要大约 5-25 微秒,但随机需要 300 微秒到 5 毫秒。
为了解决这个问题,我决定为 std::queue 和 std::priority_queue 预分配内存。
我指的是以下答案:https://stackoverflow.com/a/79433983/6319901
开发操作系统:Ubuntu 24.04 LTS。
我的目标操作系统:vxWorks 7
语言:C++17
代码:
#include <queue>
#include <array>
#include <vector>
#include <string>
#include <cstdint>
#include <iostream>
#include <functional>
static const std::size_t MAX_PACKET_LENGTH = 512;
struct receive_t
{
int data1;
float data2;
std::string data;
receive_t()
{
data.reserve(MAX_PACKET_LENGTH);
}
};
int main(int argc, char const *argv[])
{
std::cout << "Hello, World!!!\n";
std::vector<receive_t> container;
container.reserve(1000);
std::queue<receive_t,
std::vector<receive_t>> q
(
std::move(container)
);
std::cout << "sizeof(receive_t) : " << sizeof(receive_t) << std::endl;
std::cout << "sizeof(q) : " << sizeof(q) << std::endl;
std::cout << "q.size() : " << q.size() << std::endl;
return 0;
}
输出:
Hello, World!!!
sizeof(receive_t) : 40
sizeof(q) : 24
q.size() : 0
我有两个问题:
- 如何检查分配给队列的总内存?根据我的计算,
sizeof(receive_t)
必须分配 ( + 512) * 1000 字节。MAX_PACKET_LENGTH: 512
- 我可以将回调或挂钩附加到我的内存分配例程吗,这样我就可以检测到我的队列何时请求额外的内存。
您可以使用链接的技巧来获取底层容器,然后当您使用它
std::vector
作为底层容器时,您就可以获得容量。queue<T,std::vector>
不会分配。push
size < capacity
capacity * sizeof(T)
T
,请使用q.size() * 512
有没有办法访问 STL 容器适配器的底层容器?
godbolt 演示
获取分配内存的更通用的方法是使用自定义分配器,
std::vector<request_t, MyAllocator>
并且std::basic_string<char, std::char_traits<char>, MyAllocator>
在自定义分配器中您可以跟踪所有分配,否则您可以使用堆分析器来检测全局分配器并获取每个对象的内存。(我知道 valgrind 和 intel VTune 可以做到这一点)如果您想要确定性的性能,那么就不要使用
std::queue
,如果您使用std::vector
作为底层容器,那么pop
延迟取决于队列中的项目数,如果push
分配那么malloc
就非常不确定,(最坏的情况是几百微秒到一毫秒,再加上移动所有元素的时间)。相反,使用固定大小的循环缓冲区,接口的一个很好的例子是Boost.Circular Buffer,但是如果您不想使用 boost,您可以在大约 30 行中实现自己的接口,对于循环缓冲区,它们只对单个元素工作
push
并且pop
不会在运行时分配任何内存,您还可以使用对象池来池化使用的字符串以避免所有分配。确定性代码的规则之一是,不要在运行时分配内存,而只在启动时分配内存。