使用Valgrind对ros工程进行debug
问题:
在ros开发过程中出现了内存问题,系统报错
malloc(): invalid size (unsorted)这种问题非常常见,但是整个项目太大,虽然保存了任务进度,复现了问题,但是依然找不到问题的原因。
代码片段。
// An highlighted block
void DynamicVoronoi::initializeEmpty(int _sizeX, int _sizeY)
{
sizeX = _sizeX;
sizeY = _sizeY;
if (data)
delete[] data;
dataCell c;
c.dist = INFINITY;
c.sqdist = INT_MAX;
c.obstX = invalidObstData;
c.obstY = invalidObstData;
c.voronoi = free;
c.queueing = fwNotQueued;
c.needsRaise = false;
// if(sizeY==105) data = new dataCell[10];
// delete[] data;
data = new dataCell[sizeX*sizeY];//问题行
for (int x=0; x<sizeX*sizeY; x++) data[x] = c;
}
利用指令htop查看内存占用情况,发现内存5/16G,裕量不小,怀疑是其他地方的内存泄漏。
valgrind debug
ros系统中一般采用catkin_make 对工程进行编译。本工程由两个节点,一个是plane_oct,一个planner_server.
在devel/lib/planner_server文件夹下找到可执行文件,直接通过valgrind ./planner_server启动。其他节点正常采用sh文件启动。
记得planner_server包编译的时候CmakeList必须是debug模式
# SET(CMAKE_BUILD_TYPE Debug) #debug模式
SET(CMAKE_BUILD_TYPE Release) #Release
运行过程中即可得到内存相关的报错信息
==218072== Invalid write of size 1
==218072== at 0x393739: Local_planner::Optimize_Bspline() (planner.cpp:650)
==218072== by 0x39452B: main (planner.cpp:742)
==218072== Address 0x2922eb69 is 0 bytes after a block of size 6,825 alloc'd
==218072== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==218072== by 0x3B1C49: __gnu_cxx::new_allocator<signed char>::allocate(unsigned long, void const*) (new_allocator.h:114)
==218072== by 0x3AF053: std::allocator_traits<std::allocator<signed char> >::allocate(std::allocator<signed char>&, unsigned long) (alloc_traits.h:443)
==218072== by 0x3AB555: std::_Vector_base<signed char, std::allocator<signed char> >::_M_allocate(unsigned long) (stl_vector.h:343)
==218072== by 0x3A5757: std::vector<signed char, std::allocator<signed char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<signed char*, std::vector<signed char, std::allocator<signed char> > >, unsigned long, signed char const&) (vector.tcc:561)
==218072== by 0x39E2F2: std::vector<signed char, std::allocator<signed char> >::resize(unsigned long, signed char const&) (stl_vector.h:957)
==218072== by 0x393673: Local_planner::Optimize_Bspline() (planner.cpp:638)
==218072== by 0x39452B: main (planner.cpp:742)
==218072==
==218072== Invalid write of size 1
==218072== at 0x39375C: Local_planner::Optimize_Bspline() (planner.cpp:652)
==218072== by 0x39452B: main (planner.cpp:742)
==218072== Address 0x2922eb6e is 5 bytes after a block of size 6,825 alloc'd
==218072== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==218072== by 0x3B1C49: __gnu_cxx::new_allocator<signed char>::allocate(unsigned long, void const*) (new_allocator.h:114)
==218072== by 0x3AF053: std::allocator_traits<std::allocator<signed char> >::allocate(std::allocator<signed char>&, unsigned long) (alloc_traits.h:443)
==218072== by 0x3AB555: std::_Vector_base<signed char, std::allocator<signed char> >::_M_allocate(unsigned long) (stl_vector.h:343)
==218072== by 0x3A5757: std::vector<signed char, std::allocator<signed char> >::_M_fill_insert(__gnu_cxx::__normal_iterator<signed char*, std::vector<signed char, std::allocator<signed char> > >, unsigned long, signed char const&) (vector.tcc:561)
==218072== by 0x39E2F2: std::vector<signed char, std::allocator<signed char> >::resize(unsigned long, signed char const&) (stl_vector.h:957)
==218072== by 0x393673: Local_planner::Optimize_Bspline() (planner.cpp:638)
==218072== by 0x39452B: main (planner.cpp:742)
==218072==
==218072== Invalid read of size 4
==218072== at 0x393705: Local_planner::Optimize_Bspline() (planner.cpp:649)
==218072== by 0x39452B: main (planner.cpp:742)
==218072== Address 0x189d62e4 is 0 bytes after a block of size 35,700 alloc'd
==218072== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==218072== by 0x3B1A65: __gnu_cxx::new_allocator<float>::allocate(unsigned long, void const*) (new_allocator.h:114)
==218072== by 0x3AED8B: std::allocator_traits<std::allocator<float> >::allocate(std::allocator<float>&, unsigned long) (alloc_traits.h:443)
==218072== by 0x3AB135: std::_Vector_base<float, std::allocator<float> >::_M_allocate(unsigned long) (stl_vector.h:343)
==218072== by 0x3A51FF: std::vector<float, std::allocator<float> >::_M_fill_insert(__gnu_cxx::__normal_iterator<float*, std::vector<float, std::allocator<float> > >, unsigned long, float const&) (vector.tcc:561)
==218072== by 0x39E244: std::vector<float, std::allocator<float> >::resize(unsigned long, float const&) (stl_vector.h:957)
==218072== by 0x392381: Local_planner::GetMapService(bool) (planner.cpp:554)
==218072== by 0x3944F7: main (planner.cpp:738)
==218072==
V图准备前
运行过程中即可得到内存相关的报错信息
几个invalid读写大概率就是引起上文内存分配错误的原因。
相关代码片段
nav_msgs::OccupancyGrid lcpmap2d_test;
lcpmap2d_test.info.height = lcpmap2d.height;
lcpmap2d_test.info.width = lcpmap2d.width;
lcpmap2d_test.info.resolution = lcpmap2d.resolution;
lcpmap2d_test.info.origin.position.x = lcpmap2d.org_x;
lcpmap2d_test.info.origin.position.y = lcpmap2d.org_y;
lcpmap2d_test.data.resize(lcpmap2d.data.size(),100);
int size_lcp = int(lcpmap2d_test.info.height)*int(lcpmap2d_test.info.height);
float kkzs_orgx = float(lcpmap2d_test.info.origin.position.x);
float kkzs_orgy = float(lcpmap2d_test.info.origin.position.y);
float kkzs_rs = lcpmap2d_test.info.resolution;
int kkzs_x = 0 ;
int kkzs_y = 0 ;
for(int kkzs = 0;kkzs<size_lcp;kkzs++)
{
if(lcpmap2d.data[kkzs]<=-50)
lcpmap2d_test.data[kkzs] = 100; //invalid write
else
lcpmap2d_test.data[kkzs] = 0; //invalid write
}
可以发现 int size_lcp = int(lcpmap2d_test.info.height)*int(lcpmap2d_test.info.height);中尺寸错误,应该是
int size_lcp = int(lcpmap2d_test.info.height)*int(lcpmap2d_test.info.width);
小结:一般这种内存错误都以较难定位,valgrind是一个很好的工具,内存的操作有非常详细的信息。对于大多数情况,vscode debug+valgrind都可以解决问题。在段错误、弃核的情况下非常好用。
链接: link
提供了valgrind的相关指南。