CGAL中Polygon_set_2疑似内存泄漏?还是代码存在常见错误?
使用CGAL的Exact_predicates_exact_constructions_kernel和Polygon_set_2实现大量2D多边形的并集操作,为做基准测试,通过for循环重复执行该操作——每次迭代在循环内声明新的Polygon_set_2对象并添加多边形,理论上每次迭代后对象会被销毁。
但实际运行中,第一次迭代速度很快,后续迭代速度明显变慢,且内存占用随迭代次数持续上升,看起来对象销毁后内存未被释放。
代码如下:
#include <CGAL/Exact_predicates_exact_constructions_kernel.h> #include <CGAL/Polygon_2.h> #include <CGAL/Polygon_set_2.h> #include <array> #include <chrono> typedef CGAL::Exact_predicates_exact_constructions_kernel K; typedef CGAL::Polygon_2<K> Polygon_2; typedef CGAL::Polygon_set_2<K> Polygon_set_2; typedef CGAL::Point_2<K> Point; typedef std::chrono::system_clock system_clock; std::vector<std::array<double[2],3>> generate_points(int maxId); int main() { const int Runs = 10; //repeats for benchmarking const int maxId = 50; //50 x 50 x 2 polygons auto polygon_points = generate_points(maxId); //generates the coordinate points of the polygons std::cout << "Number of planned polygons " << polygon_points.size() << "\n"; std::array<Polygon_2, 50 * 50 * 2> all_polygons; //to pregenerate polygons for(size_t i = 0; i < polygon_points.size(); ++i){ for(auto pnt:polygon_points[i]){ all_polygons[i].push_back(Point(pnt[0], pnt[1])); } } //Benchmarking part. Here is the part where I suspect an error for(int run = 0; run < Runs; ++run){ Polygon_set_2 Set; std::chrono::time_point<system_clock> start = system_clock::now(); for(auto &ply:all_polygons){ Set.join(ply); } std::chrono::time_point<system_clock> end = system_clock::now(); std::chrono::duration<double> duration = end - start; std::cout << "It took " << duration.count() << " s to join " << polygon_points.size() << " polygons\n"; } return 0; } //function to generate all coodinate points of the polynoms I later want to join std::vector<std::array<double[2],3>> generate_points(int maxId){ std::vector<std::array<double[2],3>> polygons; polygons.reserve(2 * maxId * maxId); double dx{1.0/maxId}; double dy{dx}; for(int Idx = 0; Idx < maxId; ++Idx){ for(int Idy = 0; Idy < maxId; ++Idy){ polygons.emplace_back(std::array<double[2],3>{{{Idx * dx, Idy * dy},{(Idx + 1) * dx, Idy * dy},{Idx * dx, (Idy + 1) * dy}}}); polygons.emplace_back(std::array<double[2],3>{{{(Idx + 1) * dx, Idy * dy},{(Idx + 1) * dx, (Idy + 1) * dy},{Idx * dx, (Idy + 1) * dy}}}); } } return polygons; }
请问CGAL是否存在已知的内存泄漏问题?还是我可能犯了某个常见错误?
CGAL本身不存在普遍的内存泄漏问题,你的情况主要是由Exact_predicates_exact_constructions_kernel的内存池机制导致的,可通过以下方式解决:
内存池的复用策略影响
Exact_predicates_exact_constructions_kernel依赖精确算术计算,使用全局内存池管理计算过程中产生的大整数对象。默认情况下,内存池不会在对象销毁时立即释放内存,而是保留空闲内存块供后续分配复用。这会导致内存占用持续上升,但并非真正的内存泄漏——内存只是被内核缓存而非丢失。多次迭代后,内存池碎片化可能导致分配效率下降,进而使后续迭代速度变慢。手动清理内存池的解决方案
可以在每次迭代结束后,手动强制释放内存池中的空闲内存。通过调用CGAL::set_memory_pool_size(0)清空内存池,之后再恢复默认的内存池大小(如1000000),避免内存占用持续上升,同时恢复分配效率。
修改后的基准测试循环示例:
for(int run = 0; run < Runs; ++run){ Polygon_set_2 Set; std::chrono::time_point<system_clock> start = system_clock::now(); for(auto &ply:all_polygons){ Set.join(ply); } std::chrono::time_point<system_clock> end = system_clock::now(); std::chrono::duration<double> duration = end - start; std::cout << "It took " << duration.count() << " s to join " << polygon_points.size() << " polygons\n"; // 清理内存池并恢复默认大小 CGAL::set_memory_pool_size(0); CGAL::set_memory_pool_size(1000000); }
- 额外注意事项
- 确保编译时启用了CGAL的内存池支持(默认启用)。
- 若追求更准确的基准测试,可在每次迭代前增加内存预热步骤,或排除第一次冷启动的结果,清理内存池后各次迭代的速度会更接近。
内容的提问来源于stack exchange,提问作者greeny

