ROS中使用GDB和Valgrind调试

我们可以使用GDB和Valgrind对ROS程序进行调试,关键就是roslaunch中的launch-prefix参数,但是这两个工具不能同时在roslaunch中使用

GDB

可以在使用catkin_make时,添加编译类型为Debug:catkin_make -DCMAKE_BUILD_TYPE=Debug --pkg pub,另一种方法是在CMakeLists中添加下列信息,这同CMake是一样的:

1
2
3
SET(CMAKE_BUILD_TYPE "Debug")
SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")

编译后,运行命令要加--prefix参数,格式如下
1
rosrun --prefix 'gdb -ex run --args' [package_name] [node_name] 

然后会进入GDB环境运行节点。

运行结果如下,在代码第20行有一句ROS_BREAK

不过更常用的是roslaunch,除了修改CMakeLists外,还需要修改launch文件,在type之后加一句:launch-prefix="xterm -e gdb --args",也就是添加launch-prefix属性来启动node,但是注意不能通过SSH隧道启动GDB,也就是不能从本机SSH到远程机启动GDB,结果会报错,因为本机要弹出GDB的窗口

1
2
3
4
5
6
7
launch-prefix="xterm -e gdb --args" #在一个单独的xterm窗口运行节点,需要手动输入run来运行

launch-prefix="gdb -ex run --args" : 在launch程序相同的窗口运行GDB,不需要手动输入run

launch-prefix="nice" : 优化进程以减少CPU占用

launch-prefix="screen -d -m gdb --args" : 这个就是专门用于节点在另一个机器上运行,SSH登录到对方那里,使用 screen -D -R 观察GDB过程

剩下的就是GDB的使用了

Valgrind

配置很简单,除了上面修改CMakeLists,把launch中的参数修改如下:

1
launch-prefix="valgrind --leak-check=full --show-reachable=yes --undef-value-errors=yes --track-fds=yes"   		#后面的参数写在同一行

使用launch文件时,不要设置respawn为true,那样会没完没了地执行valgrind。在启动launch之后就会启动valgrind工具检测内存泄露,并执行性能分析,剩下的就是valgrind的使用了。

下面是一个简单的节点,只发布一个std_msgs消息,用valgrind测试的结果:

检查一下这个简单的程序:

1
2
3
4
5
6
7
int main(int argc, char** argv)
{
ros::init(argc,argv,"node");
ros::NodeHandle nh;
ROS_INFO("------ waiting for client's request ------");
return 0;
}

结果竟然有内存泄露:

上网一查,原来真是kinetic的bug,分析在这里,是一个指针没有delete就置为NULL,有人解决之后,在melodic没有了这个bug

nemiver

nemiver是基于GNOME的gdb前端,非常强大,但是速度有点慢。配置:launch-prefix="nemiver"

在UBUNTU下直接使用apt安装: sudo apt-get install nemiver

参考:GDB and Valgrind in ROS