fork()泄漏了吗?花更长时间来分叉一个简单的过程

sup*_*esk 18 c linux fork linux-kernel

我有一个系统,其中运行两个相同的进程(让我们称之为副本).发出信号时,副本将使用该fork()调用复制自身.第三个进程选择一个进程随机杀死,然后发信号通知另一个进程以创建替换进程.在功能上,该系统运作良好; 它可以整天杀死/重生复制品,除了性能问题.

fork()呼叫需要的时间越来越长.以下是仍然显示问题的最简单设置.时间显示在下图中:叉时间

副本的代码如下:

void restartHandler(int signo) {
// fork
  timestamp_t last = generate_timestamp();
  pid_t currentPID = fork();


  if (currentPID >= 0) { // Successful fork
    if (currentPID == 0) { // Child process
      timestamp_t current = generate_timestamp();
      printf("%lld\n", current - last);

      // unblock the signal
      sigset_t signal_set;
      sigemptyset(&signal_set);
      sigaddset(&signal_set, SIGUSR1);
      sigprocmask(SIG_UNBLOCK, &signal_set, NULL);

      return;
    } else {   // Parent just returns
      waitpid(-1, NULL, WNOHANG);
      return;
    }
  } else {
    printf("Fork error!\n");
    return;
  }
}

int main(int argc, const char **argv) {
  if (signal(SIGUSR1, restartHandler) == SIG_ERR) {
    perror("Failed to register the restart handler");
    return -1;
  }

  while(1) {
    sleep(1);
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

系统运行的时间越长,它就越糟糕.

很抱歉没有具体的问题,但有没有人知道发生了什么?在我看来,内核中存在资源泄漏(因此是linux内核标记),但我不知道从哪里开始查找.

我尝试过的:

  • 尝试kmemleak,没有抓到任何东西.这意味着如果有一些内存"泄漏",它仍然可以访问.
  • /proc/<pid>/maps 没有增长.
  • 目前使用RT补丁运行3.14内核(请注意,非rt和rt进程会发生这种情况),并且还尝试过3.2.
  • 僵尸进程不是问题.我尝试过一个版本,我使用prctl将另一个进程设置为subreaper
  • 我首先注意到系统中的这种减速,其中定时测量在重新启动的过程之外被降低; 同样的行为.

任何提示?我可以提供哪些帮助?谢谢!

sup*_*esk 4

速度减慢是由匿名 vmas 的累积引起的,并且是一个已知问题。当有大量fork()调用并且父进程在子进程之前退出时,问题就很明显。以下代码重现了该问题(来源 Daniel Forrest):

#include <unistd.h>

int main(int argc, char *argv[])
{
  pid_t pid;
  while (1) {
    pid = fork();
    if (pid == -1) {
      /* error */
      return 1;
    }
    if (pid) {
      /* parent */
      sleep(2);
      break;
    }
    else {
      /* child */
      sleep(1);
    }
  }
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

anon_vma该行为可以通过签入来确认/proc/slabinfo

有一个补丁(源代码)将复制的长度限制anon_vma_chain为五个。我可以确认该补丁修复了问题。

至于我最终是如何发现问题的,我最终开始printk在整个fork代码中进行调用,检查 中显示的时间dmesg。最终我发现是通话时间anon_vma_fork越来越长。然后就是谷歌搜索的快速问题。

这花了相当长的时间,所以我仍然感谢任何关于更好的方法来追踪问题的建议。对于所有已经花时间试图帮助我的人,谢谢你们。