AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 787802
Accepted
learningtech
learningtech
Asked: 2024-12-08 06:09:18 +0800 CST2024-12-08 06:09:18 +0800 CST 2024-12-08 06:09:18 +0800 CST

理解命令、进程和命名空间的概念

  • 772

我不是一个熟练的 Linux 用户,但我想更好地理解这篇文章中关于 Linux 命名空间的内容

https://stackoverflow.com/questions/44666700/unshare-pid-bin-bash-fork-cannot-allocate-memory

我想我的理解失败可能与对“命令”、“过程”以及其他一些内容的理解不足有关。

首先,让我解释一下我用于学习的一个简单实验。我打开了两个 PUTTY 终端窗口。在每个窗口上,我都执行了ssh root@[ip of machine]。现在,我已经与 Linux 机器建立了 2 个 SSH 会话,我开始进行实验。

在第一个窗口中,我执行了以下操作:

root@localhost:~# unshare --pid /bin/bash
bash: fork: Cannot allocate memory

在第二个窗口中,我执行了以下操作:

root@localhost:~# ps -aux | grep unshare
root       58188  0.0  0.0   6480  2284 pts/3    R+   21:49   0:00 grep --color=auto unshare

以下是我的问题:

  1. 第二个窗口没有显示任何 的迹象unshare --pid /bin/bash。这是因为/bin/bash命令或/bin/bash进程已经终止吗?这就是为什么互联网上许多 Linux 用户建议使用--fork以便/bin/bash运行在新创建的命名空间中?

  2. 接受的答案是这样的:“bash 开始运行后,bash 会 fork 几个新的子进程来做一些事情。”我不明白这句话的意思。所以在第二个终端窗口中,我运行了以下命令:

root@localhost:~# unshare -pf /bin/bash
root@localhost:~# ps -a
    PID TTY          TIME CMD
  58278 pts/2    00:00:00 sudo
  58279 pts/2    00:00:00 su
  58280 pts/2    00:00:00 bash
  58291 pts/2    00:00:00 unshare
  58292 pts/2    00:00:00 bash
  58299 pts/2    00:00:00 ps

PID 58278 到 PID58299 是不是作者所说的“bash 将分叉几个新的子进程来做一些事情”?

process
  • 1 1 个回答
  • 46 Views

1 个回答

  • Voted
  1. Best Answer
    Andy Dalton
    2024-12-08T10:41:51+08:002024-12-08T10:41:51+08:00

    背景

    我首先会简单介绍一下 Linux 中进程的创建方式。我不会介绍所有选项或所有细节,而是会重点介绍关键思想。

    通常,新进程是使用fork()系统调用创建的。成功时,fork()将产生一个新进程,该进程运行与原始进程相同的程序(实际上,它是fork()在调用时调用的程序的克隆fork())。该fork()函数在“父”进程和“子”(新创建的)进程中都返回。每个进程都可以检查的返回值fork()以确定它们是“父”还是“子”,并且它们可以使用它来决定下一步要做什么。

    通常,创建新进程意味着我们要运行不同的程序,而到目前为止,我们只有一种方法可以创建同一程序的副本。幸运的是,有一个单独的系统调用,exec()可以将当前正在运行的程序替换为新程序。

    考虑一下您有一个 shell 的情况(我bash在这里假设),并且您键入ls以列出当前目录的内容:

    (P1:bash) calls fork()
    --- the kernel creates P2 that is a copy of P1
    --- the kernel starts running P2
    
    (P1:bash) fork() returns with the PID of P2, so it knows it's the parent
    (P1:bash) Waits for P2 to finish (detailed elided)
    
    (P2:bash) fork() returns with 0, so it knows is the child
    (P2:bash) calls exec("ls")
    --- the kernel replaces bash with ls in P2 and starts ls running
    
    (P2:ls) starts running
    ...
    (P2:ls) eventually terminates
    
    (P1:bash) wakes up since P2 is finished, continues about its business
    

    问题

    你从以下开始:

    # unshare --pid /bin/bash
    bash: fork: Cannot allocate memory
    bash-5.2#
    

    注意错误bash: fork: Cannot allocate memory——这不是一个好兆头。

    在这种情况下,unshare程序 (1) 创建一个新的 PID 命名空间和 (2) execs /bin/bash。回想一下背景部分,用新程序 ( )exec 替换当前正在运行的进程( ) – 它不会创建新进程。unshare/bin/bash

    到目前为止,新创建的 PID 命名空间中还没有运行任何进程。命名空间存在,但创建命名空间的进程尚未fork()执行任何操作。

    当bash开始运行时,它通常会运行一些程序。这run是背景部分中描述的fork/exec组合。内核将第一个bash fork()进入新 PID 命名空间的进程放置在该命名空间中,该进程将成为init该命名空间的进程(该命名空间中 pid = 1 的进程)。运行的程序bash可能寿命很短,因此它会运行、终止,然后 PID 命名空间被销毁。

    接下来bash尝试运行其他命令。它想将这些命令放入新的 PID 命名空间中,但该 PID 命名空间不再存在。结果,fork()失败导致您看到的错误消息。如果您尝试运行任何其他命令,您将再次看到它:

    bash-5.2# ls
    bash: fork: Cannot allocate memory
    bash-5.2#
    

    解决方案

    正如您在问题中提到的,该unshare程序还有另一个选项,在这个场景中很有用。来自man unshare:

    -f, --fork

    将指定程序作为 的子进程分叉,unshare而不是直接运行它。这在创建新的 PID 命名空间时很有用。请注意,当unshare等待子进程时,它会忽略SIGINT并且SIGTERM不会将任何信号转发给子进程。有必要向子进程发送信号。

    您可以用以下命令替换第一个命令:

    # unshare --fork --pid /bin/bash
    #
    

    请注意,在这种情况下没有错误。

    此选项会导致unshare其行为发生变化。它不会立即使用exec()来替换自身/bin/bash,而是使用上面背景部分中描述的fork()/行为:exec()

    (P1:unshare) calls fork()
    --- the kernel creates P2 that is a copy of P1
    --- the kernel starts running P2
    
    (P1:unshare) fork() returns with the PID of P2, so it knows it's the parent
    (P1:unshare) Waits for P2 to finish (detailed elided)
    
    (P2:unshare) fork() returns with 0, so it knows is the child.
    --- P2 is running in the new PID namespace and has pid = 1
    
    (P2:unshare) calls exec("/bin/bash")
    --- the kernel replaces unshare with /bin/bash in P2 and starts ls running
    
    (P2:bash) starts running
    

    您可以通过打印其进程 ID 来确认此例中/bin/bash是init进程(即 pid 为 1 的进程):

    # echo $$
    1
    #
    

    问题的答案

    1. 第二个窗口没有显示任何 的迹象unshare --pid /bin/bash。这是因为/bin/bash命令或/bin/bash进程已经终止吗?这就是为什么互联网上许多 Linux 用户建议使用--fork以便/bin/bash运行在新创建的命名空间中?

    第二个窗口没有显示任何的迹象,unshare因为它不再运行——它曾经用exec()替换自身/bin/bash。

    该--fork选项改变了 的行为unshare,以便它fork()首先使用 创建一个新进程(新创建的 PID 命名空间中的进程),然后该进程使用exec()替换自身/bin/bash。

    1. 接受的答案是这样的:“bash 开始运行后,bash 会 fork 几个新的子进程来做一些事情。”我不明白这句话的意思。所以在第二个终端窗口中,我运行了以下命令:

    新的子流程很可能是短暂的,因此当您运行时它们不再运行ps。

    • 2

相关问题

  • 如何用名称而不是“ps”中的数字替换用户 ID 和组 ID?

  • 如何获取进程的补充组 ID?

  • `/proc/irq/.../spurious` 包含什么?

  • 父进程可以改变其子进程的环境吗?

  • “弹出”如何让进程关闭文件句柄?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve