【发布时间】:2016-11-24 10:25:47
【问题描述】:
问题
我有一个相当复杂的图像处理应用程序,其中一个子模块需要将巨大的二进制位图加载到内存中。实际上高达 96 GB(意味着 888 888 x 888 888 像素图像)。磁盘是 2xSSD raid0,读/写速度约为 1 GB/s。它将图像加载到一个向量(每个元素代表位图中的一行)中,该向量由智能指针指向带有字节的向量(每个元素代表 8 个像素)。这里奇怪的问题是,在重复加载和清除向量之后(我看到内存实际上是被填充和清除而没有内存泄漏),每次迭代似乎需要越来越长的时间。专门清理内存需要很长时间。
测试
我做了一些简单的测试应用程序来测试这个孤立的和不同的角度。 用原始指针替换智能指针会产生同样奇怪的行为。 然后我尝试使用本机数组而不是向量,这成功了。在加载/清除 100 次迭代后,使用向量时 24 GB 时间急剧增加,而数组实现在时间上是稳定的。下面是使用 24 GB 垃圾填充内存的测试应用程序,而不是加载实际图像,结果相同。在具有 128 GB RAM 并使用 Visual Studio 2013 Update 5 构建的 Windows 10 Pro 上完成的测试。
此函数使用向量进行加载/清除:
void SimpleLoadAndClear_Vector(int width, int height) {
time_t start_time, end_time;
// Load memory
time(&start_time);
cout << "Loading image into memory...";
auto width_bytes = width / 8;
auto image = new vector<vector<unsigned char>*>(height);
for (auto y = 0; y < height; y++) {
(*image)[y] = new vector<unsigned char>(width_bytes);
auto row_ptr = (*image)[y];
for (auto b = 0; b < width_bytes; b++) {
(*row_ptr)[b] = 0xFF;
}
}
cout << "DONE: ";
time(&end_time);
auto mem_load = (int)difftime(end_time, start_time);
cout << to_string(mem_load) << " sec" << endl;
// Clear memory
time(&start_time);
cout << "Clearing memory...";
for (auto y = 0; y < height; y++) {
delete (*image)[y];
}
delete image;
cout << "DONE: ";
time(&end_time);
auto mem_clear = (int)difftime(end_time, start_time);
cout << to_string(mem_clear) + " sec" << endl;
}
此函数使用数组进行加载清除:
void SimpleLoadAndClear_Array(int width, int height) {
time_t start_time, end_time;
// Load memory
time(&start_time);
cout << "Loading image into memory...";
auto width_bytes = width / 8;
auto image = new unsigned char*[height];
for (auto y = 0; y < height; y++) {
image[y] = new unsigned char[width_bytes];
auto row_ptr = image[y];
for (auto b = 0; b < width_bytes; b++) {
row_ptr[b] = 0xFF;
}
}
cout << "DONE: ";
time(&end_time);
auto mem_load = (int)difftime(end_time, start_time);
cout << to_string(mem_load) << " sec" << endl;
// Clear memory
time(&start_time);
cout << "Clearing memory...";
for (auto y = 0; y < height; y++) {
delete[] image[y];
}
delete[] image;
cout << "DONE: ";
time(&end_time);
auto mem_clear = (int)difftime(end_time, start_time);
cout << to_string(mem_clear) + " sec" << endl;
}
这是调用上述加载/清除函数的主函数:
void main()
{
auto width = 455960;
auto height = 453994;
auto i_max = 50;
for (auto i = 0; i < i_max; i++){
SimpleLoadAndClear_Vector(width, height);
}
}
经过 50 次迭代后,矢量版本的测试输出如下所示(显然加载/清除时间越来越长):
Loading image into memory...DONE: 19 sec
Clearing memory...DONE: 24 sec
Loading image into memory...DONE: 40 sec
Clearing memory...DONE: 20 sec
Loading image into memory...DONE: 27 sec
Clearing memory...DONE: 39 sec
Loading image into memory...DONE: 35 sec
Clearing memory...DONE: 24 sec
Loading image into memory...DONE: 27 sec
Clearing memory...DONE: 34 sec
Loading image into memory...DONE: 33 sec
Clearing memory...DONE: 29 sec
Loading image into memory...DONE: 27 sec
Clearing memory...DONE: 35 sec
Loading image into memory...DONE: 32 sec
Clearing memory...DONE: 33 sec
Loading image into memory...DONE: 28 sec
Clearing memory...DONE: 37 sec
Loading image into memory...DONE: 31 sec
Clearing memory...DONE: 35 sec
Loading image into memory...DONE: 30 sec
Clearing memory...DONE: 38 sec
Loading image into memory...DONE: 31 sec
Clearing memory...DONE: 38 sec
Loading image into memory...DONE: 31 sec
Clearing memory...DONE: 41 sec
Loading image into memory...DONE: 32 sec
Clearing memory...DONE: 40 sec
Loading image into memory...DONE: 33 sec
Clearing memory...DONE: 42 sec
Loading image into memory...DONE: 35 sec
Clearing memory...DONE: 43 sec
Loading image into memory...DONE: 34 sec
Clearing memory...DONE: 46 sec
Loading image into memory...DONE: 36 sec
Clearing memory...DONE: 47 sec
Loading image into memory...DONE: 35 sec
Clearing memory...DONE: 49 sec
Loading image into memory...DONE: 37 sec
Clearing memory...DONE: 50 sec
Loading image into memory...DONE: 37 sec
Clearing memory...DONE: 51 sec
Loading image into memory...DONE: 39 sec
Clearing memory...DONE: 51 sec
Loading image into memory...DONE: 39 sec
Clearing memory...DONE: 53 sec
Loading image into memory...DONE: 40 sec
Clearing memory...DONE: 52 sec
Loading image into memory...DONE: 40 sec
Clearing memory...DONE: 55 sec
Loading image into memory...DONE: 41 sec
Clearing memory...DONE: 56 sec
Loading image into memory...DONE: 41 sec
Clearing memory...DONE: 59 sec
Loading image into memory...DONE: 42 sec
Clearing memory...DONE: 59 sec
Loading image into memory...DONE: 42 sec
Clearing memory...DONE: 60 sec
Loading image into memory...DONE: 44 sec
Clearing memory...DONE: 60 sec
Loading image into memory...DONE: 44 sec
Clearing memory...DONE: 63 sec
Loading image into memory...DONE: 44 sec
Clearing memory...DONE: 63 sec
Loading image into memory...DONE: 45 sec
Clearing memory...DONE: 64 sec
Loading image into memory...DONE: 46 sec
Clearing memory...DONE: 65 sec
Loading image into memory...DONE: 45 sec
Clearing memory...DONE: 67 sec
Loading image into memory...DONE: 47 sec
Clearing memory...DONE: 69 sec
Loading image into memory...DONE: 47 sec
Clearing memory...DONE: 70 sec
Loading image into memory...DONE: 48 sec
Clearing memory...DONE: 72 sec
Loading image into memory...DONE: 48 sec
Clearing memory...DONE: 74 sec
Loading image into memory...DONE: 49 sec
Clearing memory...DONE: 74 sec
Loading image into memory...DONE: 50 sec
Clearing memory...DONE: 74 sec
Loading image into memory...DONE: 50 sec
Clearing memory...DONE: 76 sec
Loading image into memory...DONE: 51 sec
Clearing memory...DONE: 78 sec
Loading image into memory...DONE: 53 sec
Clearing memory...DONE: 78 sec
Loading image into memory...DONE: 53 sec
Clearing memory...DONE: 80 sec
Loading image into memory...DONE: 54 sec
Clearing memory...DONE: 80 sec
Loading image into memory...DONE: 54 sec
Clearing memory...DONE: 82 sec
Loading image into memory...DONE: 55 sec
Clearing memory...DONE: 91 sec
Loading image into memory...DONE: 56 sec
Clearing memory...DONE: 84 sec
Loading image into memory...DONE: 56 sec
Clearing memory...DONE: 88 sec
50次迭代后,数组版本的测试输出如下(显然加载/清除时间是稳定的,不会越来越多):
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 17 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 17 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 17 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 27 sec
Clearing memory...DONE: 17 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 17 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 17 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 17 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 19 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 17 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 26 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 25 sec
Clearing memory...DONE: 19 sec
Loading image into memory...DONE: 18 sec
Clearing memory...DONE: 25 sec
Loading image into memory...DONE: 26 sec
Clearing memory...DONE: 18 sec
问题
- 这个 Windows 是否在 处理巨大的 std::vectors?
- 是 std::vectors 只是执行蹩脚 大量数据,是否有意设计?
- 我是不是完全错过了什么?
- 是否有任何其他明显的 std 容器我应该使用(我需要通过不同线程的 x 和 y 中的索引访问图像数据)?
- 还有其他好的解释和建议的解决方案吗?
【问题讨论】:
-
你可以只保留一次内存并重复使用它吗?
-
您是在测试发布还是调试版本?
-
由于缺少 RAM,我无法测试,但可能的解释是 std::vector 在后台使用了不同的内存分配器,甚至可能是内存池,当你扔 咳咳 100GB 分配给它。
-
@Arvid 是 std::vectors 在设计上只是对大量数据执行糟糕的操作吗? -- 如果你看看你编写代码的方式,你正在创建一个向量对象并调用分配器数千次。创建对象需要构造,仅使用指针和
new不会发生这种情况。所以不是vector本身是“糟糕的”,而是你需要重新排列你的代码,这样你就不会创建太多的对象,也不会调用太多的分配器。 -
或者使用带有column/row major索引方案的单个(w x h)向量?
标签: c++ arrays windows memory vector