You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
}
  • 额外注意事项
    1. 确保编译时启用了CGAL的内存池支持(默认启用)。
    2. 若追求更准确的基准测试,可在每次迭代前增加内存预热步骤,或排除第一次冷启动的结果,清理内存池后各次迭代的速度会更接近。

内容的提问来源于stack exchange,提问作者greeny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 14:27:24