如何解决C ++ 17:内存分配/取消分配顺序中的奇怪行为
我正在用Strostrup的书学习C ++,解决了这个运动问题:
使用new测量在[1000:0]字节范围内分配10,000个随机大小的对象所需的时间(第26.6.1节);然后使用delete测量释放它们所需的时间。进行两次,一次以相反的顺序取消分配,一次以随机顺序取消。然后,执行相当于从池中分配10,000个大小为500字节的对象并释放它们的等效操作。然后,等效于在堆栈上分配[1000:0]字节范围内的10,000个随机大小的对象,然后释放它们(以相反的顺序)。比较测量值。每次测量至少要进行三次,以确保结果一致。
这是我的代码:
#include <array>
#include <algorithm>
#include <chrono>
#include <iostream>
#include <numeric>
#include <vector>
#include <random>
#include <memory_resource>
int main() {
constexpr size_t N = 1'000;
constexpr size_t SZ = 1'000;
constexpr size_t trials = 1;
std::mt19937 gen(std::random_device{}());
std::uniform_int_distribution<> sz(1,SZ);
std::array<char*,N> arr {0};
std::chrono::duration<int,std::micro> dt1 {0};
// allocate random size,deallocate in reverse order
for (size_t t = 0; t < trials; t++) {
auto t1 = std::chrono::steady_clock::now();
for (size_t i = 0; i < N; i++) {
arr[i] = new char[sz(gen)];
}
for (size_t i = N - 1; i < N; i--) {
delete arr[i];
}
auto t2 = std::chrono::steady_clock::now();
dt1 += std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
}
std::cout << dt1.count() / trials << "us\n";
std::vector<int> v (N);
std::iota(v.begin(),v.end(),0);
std::shuffle(v.begin(),gen);
std::chrono::duration<int,std::micro> dt2 {0};
// allocate random size,deallocate in random order
for (size_t t = 0; t < trials; t++) {
auto t1 = std::chrono::steady_clock::now();
for (size_t i = 0; i < N; i++) {
arr[i] = new char[sz(gen)];
}
for (size_t i = 0; i < N; i++) {
delete arr[v[i]];
}
auto t2 = std::chrono::steady_clock::now();
dt2 += std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
}
std::cout << dt2.count() / trials << "us\n";
std::pmr::unsynchronized_pool_resource pool;
std::array<std::pmr::vector<std::byte>,N> arr2;
std::chrono::duration<int,std::micro> dt3 {0};
// allocate fixed size in a pool,deallocate in reversed order
for (size_t t = 0; t < trials; t++) {
auto t1 = std::chrono::steady_clock::now();
for (size_t i = 0; i < N; i++) {
arr2[i] = std::pmr::vector<std::byte>(500,&pool);
}
for (size_t i = N - 1; i < N; i--) {
arr2[i].clear();
}
auto t2 = std::chrono::steady_clock::now();
dt3 += std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
}
std::cout << dt3.count() / trials << "us\n";
std::chrono::duration<int,std::micro> dt4 {0};
// allocate fixed size in a pool,deallocate in random order
for (size_t t = 0; t < trials; t++) {
auto t1 = std::chrono::steady_clock::now();
for (size_t i = 0; i < N; i++) {
arr2[i] = std::pmr::vector<std::byte>(500,&pool);
}
for (size_t i = 0; i < N; i++) {
arr2[v[i]].clear();
}
auto t2 = std::chrono::steady_clock::now();
dt4 += std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
}
std::cout << dt4.count() / trials << "us\n";
std::array<std::byte,N * SZ> buf;
std::chrono::duration<int,std::micro> dt5 {0};
// allocate random size in a stack,deallocate in reversed order
for (size_t t = 0; t < trials; t++) {
std::pmr::monotonic_buffer_resource pool2 {buf.data(),buf.size()};
auto t1 = std::chrono::steady_clock::now();
for (size_t i = 0; i < N; i++) {
arr2[i] = std::pmr::vector<std::byte>(sz(gen),&pool2);
}
auto t2 = std::chrono::steady_clock::now();
dt5 += std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1);
}
std::cout << dt5.count() / trials << "us\n";
}
这是我机器中使用trials = 1
并在gcc 9.1中用-O3编译的典型输出:
901us
137us
637us
210us
1018us
因此,我最初得出的结论是:“哇,以相反的顺序进行分配要比以随机的顺序进行分配要慢得多!这将是本次练习的一个教训。”
但是,事实证明这是不正确的。当我增加trial
的数量以建立平均(=一致)基准时,发生了一件奇怪的事情:
设置trials = 30
可获得:
233us
206us
348us
226us
365us
设置trials = 1'000
可获得:
167us
154us
221us
195us
194us
因此,当我一遍又一遍地分配/取消分配时,以相反的顺序进行分配不会比以随机的顺序进行分配变得特别慢!
为什么发生这种奇怪的事情?为什么第一次以相反的顺序进行重新分配比较慢?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。