Linux进程概念-详细版(一)

简介: 子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。


目录

进程概念
课本定义:进程 是程序的一个执行实例,是正在执行的程序。

但是实际上,这种说法不全面。

举个例子: 如果有一个社会人士,想要成为你们学校的学生,那么他需要满足什么样的条件呢?只需要他本人进入到你们的学校,在学校内活动就可以了吗?这显然是不行的,判断一个人是不是这个学校的学生,依据的是这个人有没有被学校所管理,学校会不会给他排课,给他计学分、发毕业证。

所以在内核观点:担当分配系统资源(CPU时间,内存)的实体。 这样描叙比较合适点。

在我们日常写代码的时候,其中有一部分内容为:编译原理。其对于一个c/c++代码,要想运行起来,要经过预处理,编译,汇编,链接。四步走,才会生成一个.exe的可执行程序,对于这个生成的.exe的可执行程序,其实就存放在磁盘上(现在的笔记本电脑仍然有磁盘作为存储设备,不过磁盘的类型和配置有所变化。根据搜索结果,笔记本电脑的磁盘主要分为固态硬盘(SSD)和机械硬盘(HDD)两种。)当我们双击这个可执行程序将其运行起来时,本质上是将这个程序加载到内存当中了,因为冯诺依曼体系的原因,只有加载到内存的数据才可以被CPU进行接下来的操作。而一旦将这个.exe程序加载到内存后,我们就不应该将这个.exe程序再叫做程序了,严格意义上将应该将其称之为进程。

在我们Windows下,我们也可以通过打开任务管理器,查看当前运行的所有进程。

不难理解的是,原本存放在磁盘上的任务管理器,经过我们打开运行后,他也会变为一个进程,这也侧面证明了我们上面说的是对的。

描述进程-PCB
系统当中可以同时存在大量进程,刚才我们在Windows下查看了当前运行的所有进程,光后台运行都有142个,可见之多。当然在Linux下也可以查看。使用命令ps aux便可以显示系统当中存在的进程。

ps aux
这里就截取一部分,其实还是蛮多的。

而当你开机的时候启动的第一个程序就是我们的操作系统(即操作系统是第一个加载到内存的),我们都知道操作系统是做管理工作的,而其中就包括了进程管理。而系统内是存在大量进程的,那么操作系统是如何对进程进行管理的呢?

遵循我们之前文章中提到的六个字原则:先描述,再组织。

操作系统管理进程也是一样的,操作系统作为管理者是不需要直接和被管理者(进程)直接进行沟通的,当一个进程出现时,操作系统就立马对其进行描述,之后对该进程的管理实际上就是对其描述信息的管理。

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,课本上称之为PCB(process control block)。

这样一来,操作系统只要拿到这个双链表的头指针,便可以访问到所有的PCB。此后,操作系统对各个进程的管理就变成了对这条双链表的一系列操作。

例如创建一个进程实际上就是先将该进程的代码和数据加载到内存,紧接着操作系统对该进程进行描述形成对应的PCB,并将这个PCB插入到该双链表当中。而退出一个进程实际上就是先将该进程的PCB从该双链表当中删除,然后操作系统再将内存当中属于该进程的代码和数据进行释放或是置为无效。
总的来说,操作系统对进程的管理实际上就变成了对该双链表的增、删、查、改等操作。

task_struct-PCB的一种
进程控制块(PCB)在描述进程的过程中,从c++这类高级编程语言来看,就是面向对象,但是Linux是用c语言来写的,所以对于PCB,他只能使用结构体。

对于task_struct,Linux中的PCB就是task_struct(在其他操作系统中的PCB就不一定叫task_struct)。
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含进程的信息。
task_struct内容分类
task_struct就是Linux当中的进程控制块,task_struct当中主要包含以下信息:

标示符: 描述本进程的唯一标示符,用来区别其他进程。
状态: 任务状态,退出代码,退出信号等。
优先级: 相对于其他进程的优先级。
程序计数器(pc): 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。\
上下文数据: 进程执行时处理器的寄存器中的数据。
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟总和,时间限制,记账号等。
其他信息。
此后所有对于进程的管理都被转换成了对数据结构PCB的增删查改,这是一个对进程的管理建模的过程。

查看进程
通过系统目录查看
在根目录下有一个名为proc的系统文件夹。

文件夹当中包含大量进程信息,其中有些子目录的目录名为数字。

ls /proc

文件夹当中包含大量进程信息,其中有些子目录的目录名为数字。

这些数字其实是某一进程的PID,对应文件夹当中记录着对应进程的各种信息。我们若想查看PID为1的进程的进程信息,则查看名字为1的文件夹即可。

通过ps命令查看
在一开始我们就是用ps aux 指令查看所有进程

那么这里我们就不单单显示效果了,就说简单解释一下这些是什么吧。此部分只是了解内容,重要的部分后面会详细说明。

含义:进程的所有者用户名,即哪个用户在系统中启动了这个进程。
示例:如果进程由 root 用户启动,显示为 root;如果是普通用户启动的进程,则会显示该普通用户的用户名。

含义:进程的 进程标识符(Process ID),是系统用来唯一标识每个运行中的进程的数字。俗称编号
示例:1234 表示进程的唯一 ID,是操作系统用来管理该进程的标识符。

含义:进程当前占用的 CPU 百分比,表示进程在系统中使用 CPU 时间的百分比。这个值是根据进程在一定时间内消耗的 CPU 时间和系统总 CPU 时间的比例计算的。
示例:如果显示为 5.0,意味着该进程在过去的 1 秒钟里,占用了系统 CPU 总量的 5%。
注意:如果是多核 CPU 系统,该百分比可能会超过 100%。例如,4 核 CPU 下,一个进程可能占用 400% 的 CPU,意味着该进程使用了 4 核的全部或多个核心的 CPU 时间。

含义:进程当前占用的 内存百分比,表示进程使用的物理内存(RAM)大小与系统总内存的比例。
示例:如果显示为 2.1,意味着该进程占用了系统总内存的 2.1%。
注意:这是基于物理内存的百分比,并不考虑交换空间(swap)。

含义:进程的 虚拟内存大小(Virtual Memory Size),单位为 KB。这个值包括进程使用的所有内存(包括共享库、映射文件等),以及可能存在的虚拟内存空间(比如被交换到硬盘上的内存)。
示例:123456 表示该进程的虚拟内存占用了 123456 KB。

含义:进程的 常驻内存集(Resident Set Size),单位为 KB。RSS 表示进程当前在物理内存中占用的实际内存(不包括交换到磁盘的部分),也就是进程占用的非虚拟内存部分。
示例:23456 表示该进程的 RSS 为 23456 KB。

含义:进程所关联的 终端(Terminal),表示该进程是在哪个终端下启动的。如果进程没有终端(如后台进程或系统进程),这个字段显示为 ?。
示例:tty1 表示该进程是在 tty1 终端上运行;? 表示该进程没有关联终端。

这部分后面细讲,再次省略。

含义:进程的 启动时间,表示该进程开始运行的时间。格式通常是 小时:分钟(对于启动时间较短的进程)或 日期(对于启动时间较长的进程)。
示例:12:34 表示该进程在 12:34 启动;Nov 28 表示该进程在 11 月 28 日启动。

含义:进程已经使用的 CPU 时间,即该进程自启动以来占用的总 CPU 时间,通常以 分钟:秒 的形式显示。
示例:00:02 表示该进程已占用了 2 秒钟的 CPU 时间。

含义:启动进程的 命令,即运行该进程的完整命令行(包括路径和参数)。对于较长的命令行,可能只会显示部分内容,如果需要查看完整命令行,可以使用 ps auxww 来显示完整内容。
示例:/usr/bin/python3 /path/to/script.py 表示该进程是运行 Python 脚本。
在Windows下我们也通过实践得知,我们使用任务管理器查看当前运行的所有进程的时候,此时被打开的任务管理器也会变为进程,那么,同样我们在使用ps命令查看当前的进程时候,也会将ps作为一个进程运行起来。

此时我们就可以ps命令与grep -V grep命令搭配使用,即可只显示某一进程的信息,从而过滤ps命令。

ps aux | head -1 && ps aux | grep proc | grep -v grep

通过系统调用获取进程的PID和PPID
通过使用系统调用函数,getpid和getppid即可分别获取进程的PID和PPID。

这里我们就不man 来查看原文的介绍了,这里直接解释getpid与getppid是什么,

getpid是返回其当前进程的pid
getppid是返回当前进程的ppid,ppid也就是其当前进程的父进程的pid
需要引用头文件#include

当运行该代码生成的可执行程序后,便可循环打印该进程的PID和PPID。

我们可以通过ps命令查看该进程的信息,即可发现通过ps命令得到的进程的PID和PPID与使用系统调用函数getpid和getppid所获取的值相同。

注意:aux是显示详细信息,ajx显示的稍微少一点。我这里用的是ajx,不是aux,其实用aux也行,只是这里不需要显示详细信息,所有用ajx就可以。

通过系统调用创建进程
fork的认识
在以前,我们熟悉的创建进程的方式有两种,第一种是在Windows系统下,我们双击一个 .exe 文件,就创建了一个进程,还有一种是在Linux系统下,我们通过在命令行输入 ./ 来将程序变成进程去运行

现在我们再来学习一种创建进程的方式,通过系统调用:fork

同样不man查看官方的解释,直接用案例来演示

我们写一个这样的代码,然后运行查看效果

若是代码当中没有fork函数,我们都知道代码的运行结果就是循环打印该进程的PID和PPID。而加入了fork函数后,代码运行结果如下:

可以看到也是打印了独两份,二者不会相互干扰,其中蓝色标识的ppid为红色标识的pid,拿着也在侧面说明了,其蓝色指向的进程的父进程为红色指向的进程。也就是说test1进程与fork函数创建的进程之间是父子关系。

每出现一个进程,操作系统就会为其创建PCB,fork函数创建的进程也不例外。

我们知道加载到内存当中的代码和数据是属于父进程的,那么fork函数创建的子进程的代码和数据又从何而来呢?
我们看看以下代码的运行结果:

运行结果:

实际上,使用fork函数创建子进程,在fork函数被调用之前的代码被父进程执行,而fork函数之后的代码,则默认情况下父子进程都可以执行。需要注意的是,父子进程虽然代码共享,但是父子进程的数据各自开辟空间(采用写时拷贝,也就是说如果不做任何修改的情况下还是共用)。

特别提醒: 使用fork函数创建子进程后就有了两个进程,这两个进程被操作系统调度的顺序是不确定的,这取决于操作系统调度算法的具体实现。

使用if进行分流
上面说到,fork函数创建出来的子进程与其父进程共同使用一份代码,但是如果让父进程创建的子进程与父进程做着完全相同的事情,那么这就显得子进程没有存在的意义。

所以实际上,我们创建子进程的目的就是为了让其与父进程做着完全不同的事,想要达到这点要求,还是需要先了解其fork函数的返回值。

fork函数的返回值:

如果子进程创建成功,在父进程中返回子进程的PID,而在子进程中返回0。
如果子进程创建失败,则在父进程中返回 -1。

既然父进程和子进程获取到fork函数的返回值不同,那么我们就可以据此来让父子进程执行不同的代码,从而做不同的事。

fork创建出子进程后,子进程会进入到else if 语句的循环打印当中,而父进程会进入到 else语句的循环打印当中。

最后的总结
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。
为什么要创建子进程:为了让其父子进程执行不同的代码块。
子进程的数据相对于父进程是会进行写时拷贝(COW)。
Linux进程状态
一个进程从创建到撤销的整个生命周期中,体现了进程与程序之间的区别。尽管在同一台机器上可以同时运行多个进程,有些进程可能正在占用处理器执行,而另一些进程则处于等待状态,无法获得处理器资源。即使有空闲的处理器,由于某些条件尚未满足,这些进程仍然无法执行。这一切都表明,进程是动态的,并且具有状态变化的特性,因此引入了“进程状态”这一概念。

这里我们具体谈一下Linux操作系统中的进程状态,Linux操作系统的源代码当中对于进程状态有如下定义:

/*

  • The task state array is a strange "bitmap" of
  • reasons to sleep. Thus "running" is zero, and
  • you can test for combinations of others with
  • simple bit tests.
    /
    static const char
    task_state_array[] = {
    "R (running)", / 0/
    "S (sleeping)", / 1/
    "D (disk sleep)", / 2/
    "T (stopped)", / 4/
    "t (tracing stop)", / 8/
    "Z (zombie)", / 16/
    "X (dead)" / 32/
    };
    小提醒: 进程的当前状态是保存到自己的进程控制块(PCB)当中的,在Linux操作系统当中也就是保存在task_struct当中的。

在Linux操作系统当中我们可以通过 ps aux 或 ps axj 命令查看进程的状态。

ps aux

ps ajx

运行状态-R
运行状态根据名字也不难理解,但是在实际上,一个进程处于运行状态(running),并不意味着进程一定处于运行当中,运行状态表明一个进程要么在运行中,要么在运行队列里。也就是说,可以同时存在多个R状态的进程。

但是如果自己去实验,ps一个当前运行的进程,可能我们查看到的并不是R状态。

这是因为:进程在CPU上运行的时候,并不是一直在运行的,而是一个进程先在CPU上运行一会(大概时10ms),再切换另一个进程在CPU上运行一会,不断的切换进程周而复始重复运作的。这叫做基于进程切换的分时操作系统,由于CPU的运行速度非常快,切换速度使人类感觉不到,从而使人们有种进程一直在运行的感觉。所以在实际上可能在那1ms内该进程时运行的,但是在下一ms又不运行了,又可能有过了几ms又运行了,然后实际算下来不运行的时间比运行的长,所以在查看的时候,不是R状态。

浅度睡眠状态-S
一个进程处于浅度睡眠状态(sleeping),意味着该进程正在等待某件事情的完成,处于浅度睡眠状态的进程随时可以被唤醒,也可以被杀掉(这里的睡眠有时候也可叫做可中断睡眠(interruptible sleep))。(杀死进程可以使用kill指令然后指定杀死对应的进程)

代码当中调用sleep函数进行休眠20秒,在这期间我们若是查看该进程的状态,则会看到该进程处于浅度睡眠状态。

ps aux | head -1 && ps aux | grep test2 | grep -v grep

而处于浅度睡眠状态的进程是可以被杀掉的,我们可以使用kill命令将该进程杀掉。

这里的-9是以编号为9的杀死方式去kill。

深度睡眠状态-D
一个进程处于深度睡眠状态(disk sleep),表示该进程不会被杀掉,即便是操作系统也不行,只有该进程自动唤醒才可以恢复。该状态有时候也叫不可中断睡眠状态(uninterruptible sleep),处于这个状态的进程通常会等待IO的结束。

例如,某一进程要求对磁盘进行写入操作,那么在磁盘进行写入期间,该进程就处于深度睡眠状态,是不会被杀掉的,因为该进程需要等待磁盘的回复(是否写入成功)以做出相应的应答。(磁盘休眠状态)。

暂停状态-T
在Linux当中,我们可以通过发送SIGSTOP信号使进程进入暂停状态(stopped),发送SIGCONT信号可以让处于暂停状态的进程继续运行。

例如,我们对一个进程发送SIGSTOP信号,该进程就进入到了暂停状态。

S 状态表示 中断睡眠(Interruptible Sleep),即进程正在等待某个事件,且可以被信号中断。
S+ 状态表示 中断睡眠,并且该进程是 前台进程组的一部分,通常与终端操作相关。

暂停状态-t
这个没什么好解释的,这个就是其在调试代码的时候,遇见断点,就会变为此状态,但是实际上在vim中很少调试,能直接观察出代码问题的话,都是不建议调试。

死亡状态-X
死亡状态只是一个返回状态,当一个进程的退出信息被读取后,该进程所申请的资源就会立即被释放,该进程也就不存在了,所以你不会在任务列表当中看到死亡状态(dead)。

僵尸状态-Z (子退出)
当一个进程终止时,操作系统并不会立即释放其占用的所有资源。此时进程会进入僵尸状态(Zombie),保留其退出状态等信息,直到父进程通过wait()系列函数读取这些信息。在此期间,内核会保留该进程的进程描述符等最小量信息。如果父进程始终不读取子进程的退出状态,这些残留信息将一直存在于系统中。(关于读取退出信息的工作是要有父进程来做,读取方式是调用函数wait()函数(后面介绍))

首先,僵尸状态的存在是必要的,因为进程被创建的目的就是完成某项任务,那么当任务完成的时候,调用方是应该知道任务的完成情况的,所以必须存在僵尸状态,使得调用方得知任务的完成情况,以便进行相应的后续操作。

那么我再这里提到了c语言的main函数,那么肯定是想靠拢僵尸进程的。

虽然在 C 语言代码中,main 函数是程序的入口点,但从操作系统的角度来看,main 函数并不是程序的“最外层”。实际上,main 函数是操作系统加载并运行程序后,交给程序的一部分,操作系统在背后执行了许多准备工作,确保程序能够顺利启动和执行(也就是去调用main函数,这也就是为什么一个项目只能有一个main函数)。

那么如果main函数的父进程没有处理main函数的退出信息,在理论上main函数同样会变为僵尸进程,但是在实际情况上,这种事情根本不会发生。

以上说了那么多,其实都在解释其实main函数也是一个进程,其也有存在变为僵尸进程的风险。只不过这种风险根本不可能发生。

那么,这个0就是返回给操作系统的,告诉操作系统代码顺利执行结束。在Linux操作系统当中,我们可以通过使用echo $?命令获取最近一次进程退出时的退出码。

echo $?

所以总的来说如果一个子进程结束时,立刻退出,父进程是没有机会拿到退出结果的。所以在Linux中,子进程退出时,一般不会立即彻底退出,而是要维持一个 Z 状态,也叫僵尸状态,方便后续父进程读取该子进程的退出结果。

补充: 进程退出的信息(例如退出码),是暂时被保存在其进程控制块当中的,在Linux操作系统中也就是保存在该进程的task_struct当中。

僵尸进程
前面说到,当一个子进程终止后,其退出状态信息会被内核保留,直到父进程通过wait()系列函数读取这些信息。在此期间,该子进程处于僵尸状态(Zombie)。如果父进程先于子进程终止,子进程会被init进程(PID 1)接管,此时init进程将负责处理这些僵尸进程。

简单来说,僵尸状态就像是子进程留给父进程的'临终遗言'。当子进程死亡(终止)后,它会变成僵尸——这不是真的活着,只是暂时保留死亡原因(退出状态),等着父进程来'收尸'(调用wait读取状态)。只有父进程完成这个'殡葬仪式',子进程才会被系统彻底回收。如果父进程一直不来收尸,这个僵尸就会一直占着系统资源不放手。

例如,对于以下代码,创建一个维持30s的僵尸进程的例子

运行该代码后,我们可以通过以下监控脚本,每隔一秒对该进程的信息进行检测

while :; do ps aux | head -1; ps aux | grep test4 | grep -v grep; sleep 1; done

僵尸进程的危害
僵尸进程的退出状态必须一直维持下去,因为它要告诉其父进程相应的退出信息。可是父进程一直不读取,那么子进程也就一直处于僵尸状态。
僵尸进程的退出信息被保存在task_struct(PCB)中,僵尸状态一直不退出,那么PCB就一直需要进行维护。
若是一个父进程创建了很多子进程,但都不进行回收,那么就会造成资源浪费,因为数据结构对象本身就要占用内存。
僵尸进程申请的资源无法进行回收,那么僵尸进程越多,实际可用的资源就越少,也就是说,僵尸进程会导致内存泄漏。
到这里值得被关注的进程状态已经讲解完毕,那么下面就是属于补充知识了,说一些别的状态(这些知识虽没有放在前面说,但是也是十分的重要,不是了解内容,是掌握的内容,非常重要!!!)

孤儿进程
在Linux当中的进程关系大多数是父子关系,若子进程先退出而父进程没有对子进程的退出信息进行读取,那么我们称该进程为僵尸进程。但若是父进程先退出,那么将来子进程进入僵尸状态时就没有父进程对其进行处理,此时该子进程就称之为孤儿进程。
若是一直不处理孤儿进程的退出信息,那么孤儿进程就会一直占用资源,此时就会造成内存泄漏。因此,当出现孤儿进程的时候,孤儿进程会被1号init进程领养,此后当孤儿进程进入僵尸状态时就由int进程进行处理回收。

例如,对于以下代码,fork函数创建的子进程会一直打印信息,而父进程在打印5次信息后会退出,此时该子进程就变成了孤儿进程。

重要知识补充:阻塞和挂起
一个进程可以有多个状态,我们先来说明两个最为核心的状态:阻塞和挂起。

以下解释来源于别人写的文章。

阻塞
进程因为等待某种条件就绪,而导致的一种不推进的状态叫做阻塞状态,给人们最直观的感受就是程序卡住了。换句话说,一个进程阻塞,一定是在等待某种所需要的资源就绪的过程。

想象这样一个场景,我们在下载一些资料的时候,如果网断了,CPU还有必要继续调度这个下载进程吗?肯定是没必要了,因为没有意义,此时就会把该进程设置为阻塞状态。那么这个进程是如何等待网络资源就绪的呢?

首先再在这里提及一个知识点,在Linux操作系统下,一切设备皆文件,那么比如我们日常所说的显示器,其实他也在操作系统面前也是文件,他是文件,他就一定会被管理。

我们之前讲过,操作系统需要管理网卡、磁盘等外设,这个过程通常是一个“先描述再组织”的过程。操作系统会创建多个结构体类型(如 struct dev),然后将各个外设的属性信息填充到这些结构体中,接着通过数据结构将它们组织在一起。同样地,操作系统管理大量的进程时,也是通过“先描述再组织”的方式进行的。具体而言,操作系统会定义多个结构体来描述进程的各种属性,并将这些进程通过链表、队列等数据结构进行组织和调度。

当网络断开时, 需要等待网络资源的进程就会把自己的PCB从CPU的某些特定队列中拿取出来,连接到网卡设备结构体队列的尾部来排队等待网络资源:

此时,再获取到等待的资源之前,该进程不会再被CPU调度。

PCB是可以被维护在不同的队列中的。进程在等待哪种资源,就会被排列到哪种资源的队列中去。再举个例子,当我们在C语言中使用scanf 函数时,运行程序,如果我们不在键盘上输入内容,进程就会处于阻塞状态,并在键盘的结构体中排队等待资源,只有拿到数据时,进程才会再次被CPU调度。

总结:阻塞就是不被CPU调度——一定是因为当前进程需要等待某种资源就绪——一定是进程tesk_struct结构体需要在某种被OS管理的资源下排队。

挂起
如果有时候出现了内存资源紧张的情况,而且阻塞进程的PCB被接入到了所需要等待资源的结构体队列中,不被调度。这时,操作系统就会把阻塞进程的代码和数据交换到磁盘中,同时释放其所在内存中占据的空间,从而起到节省内存空间的目的。等到进程所需要的资源就绪的时候,再把该进程的代码和数据加载到内存中,交由CPU调度。

其中把进程的代码和数据由OS暂时性的交换到磁盘中时,称该进程处于挂起状态。全称为阻塞挂起状态。挂起可以看作一种特殊的阻塞状态。

比如在我们生活中,一边走路一边玩手机很危险,所以此时我们会将玩手机这个 进程挂起 ,即把手机揣进兜里,然后 专心执行走路这个 进程。

二者区别
是否释放CPU:阻塞(pend)就是任务释放CPU,其他任务可以运行,一般在等待某种资源或信号量的时候出现。挂起(suspend)不释放CPU,如果任务优先级高就永远轮不到其他任务运行。一般挂起用于程序调试中的条件中断,当出现某个条件的情况下挂起,然后进行单步调试。
是否主动:显然阻塞是一种被动行为,其发生在磁盘,网络IO,wait,lock等要等待某种事件的发生的操作之后。因为拿不到IO资源,所以阻塞时会放弃 CPU的占用。而挂起是主动的,因为挂起后还要受到CPU的监督(等待着激活),所以挂起不释放CPU,比如sleep函数,站着CPU不使用。

目录
相关文章
|
2月前
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
117 16
|
3月前
|
并行计算 Linux
Linux内核中的线程和进程实现详解
了解进程和线程如何工作,可以帮助我们更好地编写程序,充分利用多核CPU,实现并行计算,提高系统的响应速度和计算效能。记住,适当平衡进程和线程的使用,既要拥有独立空间的'兄弟',也需要在'家庭'中分享和并行的成员。对于这个世界,现在,你应该有一个全新的认识。
193 67
|
2月前
|
Web App开发 Linux 程序员
获取和理解Linux进程以及其PID的基础知识。
总的来说,理解Linux进程及其PID需要我们明白,进程就如同汽车,负责执行任务,而PID则是独特的车牌号,为我们提供了管理的便利。知道这个,我们就可以更好地理解和操作Linux系统,甚至通过对进程的有效管理,让系统运行得更加顺畅。
79 16
|
2月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
74 20
|
1月前
|
监控 Shell Linux
Linux进程控制(详细讲解)
进程等待是系统通过调用特定的接口(如waitwaitpid)来实现的。来进行对子进程状态检测与回收的功能。
48 0
|
1月前
|
存储 负载均衡 算法
Linux2.6内核进程调度队列
本篇文章是Linux进程系列中的最后一篇文章,本来是想放在上一篇文章的结尾的,但是想了想还是单独写一篇文章吧,虽然说这部分内容是比较难的,所有一般来说是简单的提及带过的,但是为了让大家对进程有更深的理解与认识,还是看了一些别人的文章,然后学习了学习,然后对此做了总结,尽可能详细的介绍明白。最后推荐一篇文章Linux的进程优先级 NI 和 PR - 简书。
43 0
|
1月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
38 0
|
4月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
155 4
|
4月前
|
Linux 数据库 Perl
【YashanDB 知识库】如何避免 yasdb 进程被 Linux OOM Killer 杀掉
本文来自YashanDB官网,探讨Linux系统中OOM Killer对数据库服务器的影响及解决方法。当内存接近耗尽时,OOM Killer会杀死占用最多内存的进程,这可能导致数据库主进程被误杀。为避免此问题,可采取两种方法:一是在OS层面关闭OOM Killer,通过修改`/etc/sysctl.conf`文件并重启生效;二是豁免数据库进程,由数据库实例用户借助`sudo`权限调整`oom_score_adj`值。这些措施有助于保护数据库进程免受系统内存管理机制的影响。
|
4月前
|
Linux Shell
Linux 进程前台后台切换与作业控制
进程前台/后台切换及作业控制简介: 在 Shell 中,启动的程序默认为前台进程,会占用终端直到执行完毕。例如,执行 `./shella.sh` 时,终端会被占用。为避免不便,可将命令放到后台运行,如 `./shella.sh &`,此时终端命令行立即返回,可继续输入其他命令。 常用作业控制命令: - `fg %1`:将后台作业切换到前台。 - `Ctrl + Z`:暂停前台作业并放到后台。 - `bg %1`:让暂停的后台作业继续执行。 - `kill %1`:终止后台作业。 优先级调整:
222 5