strace

我们通常使用 strace 命令跟踪一个命令的执行,strace常用来跟踪进程执行时的系统调用和所接收的信号

strace的语法很简单:

strace [参数] <命令>

strace 会拦截<命令>中和内核的交互并且打印,其中每一行代表一个系统调用,包括它的名字、参数以及返回值

常用参数表速查

参数功能描述典型用途
-p <PID>附加(Attach)到正在运行的进程诊断运行中突然卡住的后台服务
-o <file>将输出保存到文件方便之后用 vimgrep 详细分析
-e <expr>过滤特定的系统调用只看文件操作:-e trace=openat,read
-f跟踪子进程(Follow forks)调试会产生多个进程的复杂程序(如 Nginx)
-c统计模式汇总每个系统调用的次数、错误和耗时
-T显示每个调用消耗的时间寻找性能瓶颈,看哪一步最慢

下面举个例子讲解 strace 如何展现程序与内核的通信

我们用一个go语言程序实现一个Hello world的打印

out

通过这些输出我们能发现:

  • 所有命令的开头都是 execve ,这是linux加载程序的标准方式
  • go程序会预先分配很多的虚拟内存,所以会出现很多的 mmap 向内核申请空间
  • go会在运行前观察自己的环境,会尝试去读取 Cgroups 配置从而知道自己被分配了多少CPU,从而自动决定开启多少线程
  • go几乎接管了所有可能的系统信号,从而实现抢占式调度和GC触发
  • 在接近最后的 write(1,"Hello world\n",12) 才是代码中的fmt.Println