如果内核作为线程产生并驻留在内存中,那么ps
如果它们不是正常进程,命令如何识别它们?我会在这里给你更多信息:
root 2 0 0 févr.04 ? 00:00:00 [kthreadd]
root 3 2 0 févr.04 ? 00:00:01 [ksoftirqd/0]
root 5 2 0 févr.04 ? 00:00:00 [kworker/0:0H]
我们看到的那些内核线程具有与 Linux 进程子进程 ID、父进程 ID(为 0)和用户所有者(即 root)相同的信息
请解释一下。
因此,如果这些线程以不同的方式执行,CPU 如何区分内核线程和内存中的 Linux 进程 elf 可执行文件或库,我需要知道这一点。
另一个问题:当编译器构建可执行文件时,它会创建一个 vma(虚拟内存地址),然后 CPU 会使用它来分配内存空间;编译器如何生成这些地址?
感谢你们。
答案1
对于 Linux,我无法明确回答“内核线程”问题。对于 Windows,我可以告诉您,“内核线程”只是从其他内核模式例程创建的线程,运行永远不会进入用户模式的程序。当调度程序选择一个线程执行时,它会恢复其先前的状态(用户或内核,无论它是什么);CPU 不需要“分辨出区别”。线程在内核模式下执行,因为这就是它正在做的事情最后的执行的时间。
在 Windows 中,这些线程通常以所谓的“系统”进程作为父进程来创建,但实际上它们可以在任何进程中创建。那么,在 Unix 中,它们的父 ID 可以是零?即不属于任何进程?这实际上无关紧要,除非线程尝试使用进程级资源。
至于编译器分配的地址... 有几种可能的方式来考虑这个问题。其中一部分是编译器实际上不会选择地址对于大多数事物而言;编译器生成的几乎所有内容(在现代环境中)都是以偏移量表示的。给定的局部变量与例程实例化时堆栈指针所在的位置存在某个偏移量。(请注意,堆栈本身位于动态分配的地址,就像堆分配一样。)例程入口点与它所在的代码段的开头存在某个偏移量。等等。
答案的第二部分是,地址(例如地址)是由链接器而不是编译器分配的。这实际上只是推迟了问题 - 它如何做到这一点?我猜你的意思是,它如何知道运行时哪些地址可用?答案是“几乎所有地址。”
请记住,每个进程都是从几乎完全空白的状态开始的,具有用户模式地址空间的新实例。例如,每个进程都有自己的 0x10000 实例。因此,除了必须避免平台上每个进程中位于众所周知(无论如何对链接器而言)位置的某些事物之外,链接器可以自由地将事物放置在进程地址空间中所需的位置。它不必知道或关心其他任何东西已经在哪里。
第三部分是,几乎所有东西(除了那些位于众所周知地址的操作系统定义的东西)都可以在运行时移动到不同的地址,这是由于地址空间布局随机化,它同时存在于 Windows 和 Linux 上(事实上,Linux 首先发布了它)。因此,链接器将内容放在哪里实际上并不重要。