运行rosrun时出现munmap_chunk()无效指针错误,未使用malloc/free
解决
munmap_chunk(): invalid pointer错误的分析与修复 问题背景
运行ROS节点时触发munmap_chunk(): invalid pointer错误,节点功能为接收点云与costmap数据,检测洞穴后修改costmap实现move_base避障。已使用智能指针、添加mutex同步,但问题仍存在。
错误根源分析
从代码中排查出以下核心问题,直接导致内存损坏:
- 未定义的函数返回行为:
Hole_fn函数声明返回nav_msgs::OccupancyGrid,但当input_cloud_p.size() <= 0时无返回语句,破坏栈结构引发指针错误。 - 错误的坐标转换逻辑:直接将点云世界坐标强转为costmap栅格坐标,未使用
costmap_2d::Costmap2D::worldToMap()做正确转换,导致索引越界、非法访问内存。 - 全局
tf_costmap频繁赋值风险:全局costmap_2d::Costmap2D对象在循环中被频繁赋值,其内部内存管理逻辑可能因重复赋值导致指针混乱。 - 大对象无意义值传递:
cambia函数的costmap_data采用值传递,每次调用拷贝整个大对象,既浪费资源又易引发拷贝/销毁过程中的内存错误。 - 局部
tf::TransformListener生命周期问题:cambia函数内每次创建局部监听器,其生命周期与ROS节点上下文不匹配,引发潜在内存或通信问题。
修复方案与代码修改
1. 修复Hole_fn的返回值问题
确保函数所有分支都有返回值:
nav_msgs::OccupancyGrid Hole_fn(pcl::PointCloud<pcl::PointXYZ>& input_cloud_p, nav_msgs::OccupancyGrid& costmap_data_p, pcl::PointCloud<pcl::PointXYZ>& nube_filt_p) { ros::spinOnce(); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_out_ptr(new pcl::PointCloud<pcl::PointXYZ>); pcl::VoxelGrid<pcl::PointXYZ> sor; sor.setInputCloud(input_cloud_p.makeShared()); sor.setLeafSize(0.1, 0.1, 0.1); sor.filter(*cloud_out_ptr); if(input_cloud_p.size() > 0) { return cambia(*cloud_out_ptr, costmap_data_p, nube_filt_p); } // 所有路径返回有效值,这里返回原costmap return costmap_data_p; }
2. 修正坐标转换逻辑
使用worldToMap()完成世界坐标到栅格坐标的转换,避免索引越界:
// 替换cambia函数循环内的坐标处理逻辑 double world_x = point.x; double world_y = point.y; int grid_x, grid_y; if(tf_costmap.worldToMap(world_x, world_y, grid_x, grid_y)) { // 坐标转换有效时才执行修改 std::lock_guard<std::mutex> lock(mtx); tf_costmap.setCost(grid_x, grid_y, costmap_2d::LETHAL_OBSTACLE); }
3. 避免全局tf_costmap频繁赋值
将tf_costmap改为智能指针管理,避免全局对象的赋值风险:
// 修改convertirACostmap2D函数返回智能指针 std::shared_ptr<costmap_2d::Costmap2D> convertirACostmap2D(nav_msgs::OccupancyGrid& occupancy_grid) { auto costmap_data = std::make_shared<costmap_2d::Costmap2D>( occupancy_grid.info.width, occupancy_grid.info.height, occupancy_grid.info.resolution, occupancy_grid.info.origin.position.x, occupancy_grid.info.origin.position.y ); for(unsigned int x = 0; x < occupancy_grid.info.width; ++x) { for(unsigned int y = 0; y < occupancy_grid.info.height; ++y) { int8_t occupancy_value = occupancy_grid.data[x + y * occupancy_grid.info.width]; unsigned char cost = costmap_2d::FREE_SPACE; if (occupancy_value == 100) { cost = costmap_2d::LETHAL_OBSTACLE; } else if (occupancy_value > 0) { cost = costmap_2d::INSCRIBED_INFLATED_OBSTACLE; } costmap_data->setCost(x, y, cost); } } return costmap_data; }
4. 修改参数传递方式为引用
将cambia函数的costmap_data改为引用传递,避免大对象拷贝:
nav_msgs::OccupancyGrid cambia(pcl::PointCloud<pcl::PointXYZ>& input_cloud, nav_msgs::OccupancyGrid& costmap_data, pcl::PointCloud<pcl::PointXYZ>& nube_filter) { // 函数逻辑保持不变,仅修改参数类型 }
5. 全局初始化tf::TransformListener
在全局作用域初始化监听器,确保生命周期与节点一致:
// 全局变量定义 std::mutex mtx; tf::TransformListener tf_listener; // 全局初始化,避免局部创建的生命周期问题
额外建议
- 启用编译器警告选项(如
-Wall -Wextra),提前发现未定义返回值、类型转换等问题。 - 使用
valgrind工具检测内存问题:valgrind --leak-check=full rosrun your_package your_node
内容的提问来源于stack exchange,提问作者Diego
相关产品推荐
相关产品推荐

