Linux进程【补充】

文章目录

  • 进程概念
    • task_struct
  • 进程创建
    • fork
    • vfork
    • 写时拷贝
  • 进程状态
    • 僵尸进程
    • 孤儿进程
    • 守护进程
  • 进程地址空间
    • 是什么
    • 为什么
    • 怎么做


进程概念

进程是一个程序的执行实例或者是担当系统资源分配的实体。当一个程序运行时,被从硬盘加载到内存中,操作系统为每个程序运行定义了描述信息,通过这个描述信息来控制和管理程序的运行,因此对于操作系统来说,pcb就是进程,而Linux的pcb是task_struct。所有运行在系统里的进程都以task_struct链表的形式存在内核里。

在这里插入图片描述

进程 = 内核关于进程的数据结构 + 当前进程的代码 + 数据

task_struct

task_struct是Linux内核中用于表示进程(或线程)的数据结构。在Linux内核源代码中,task_struct结构体定义了进程的各种属性和状态信息,包括进程的标识、调度信息、内存管理信息等。

  1. 进程标识符(PID): 每个进程在系统中都有一个唯一的PID,用于区分和标识不同的进程。

  2. 进程状态: 进程可能处于运行态、就绪态、睡眠态、停止态等不同的状态,task_struct中会记录当前进程的状态。

  3. 进程调度信息: 包括进程的优先级、调度策略、调度器相关的信息等。

  4. 进程描述符: 描述进程的各种属性和信息,如进程名称、用户标识、组标识等。

  5. 进程的父子关系: 指向父进程和子进程的指针,用于建立进程之间的父子关系链表。

  6. 地址空间信息: 包括进程的虚拟地址空间、页表信息等。

  7. 文件描述符表: 记录进程打开的文件以及文件的状态信息。

  8. 信号处理器: 记录进程注册的信号处理函数以及当前信号的状态。

  9. 调度器相关信息: 与进程调度相关的一些附加信息,如调度实体、调度策略等。

  10. 内存管理信息: 包括进程在内存中的分配情况、内存页的状态等。

进程创建

fork

fork()函数用于创建进程。当一个进程(父进程)调用fork()函数时,它创建了一个新的进程(子进程)。这个新的子进程几乎是父进程的完整副本:它继承了父进程的地址空间、进程环境、打开的文件描述符等资源。不过,父进程和子进程有不同的进程ID,并且它们的内存是分开的。

当调用fork()时,操作系统做了以下几步:

  1. 分配新的进程ID(PID)给子进程。
  2. 复制父进程的地址空间到子进程,包括代码段、数据段和堆栈。
  3. 复制父进程的进程控制块(PCB),包括文件描述符、信号处理方式等。
  4. 为子进程分配独立的内存空间。

fork()函数的返回值:

  • 对于父进程fork()返回新创建子进程的进程ID(PID>0)。
  • 对于子进程fork()返回0。
  • 错误情况:如果出现错误,fork()返回-1,并设置errno以指示错误原因。

注意事项

  • fork()之后,父子进程各自独立执行,但是由于地址空间的复制,它们会从fork()调用的下一条指令开始执行。
  • 父子进程间共享文件描述符,如果不希望共享,需要在fork()之后,exec()之前调用close()
  • fork()可能会因为系统资源不足而失败。
  • 创建进程后,父进程通常会调用wait()waitpid()等待子进程结束,避免僵尸进程的产生。

vfork

vfork()用于创建一个新进程,但是与fork()有所不同。vfork()是"虚拟fork"的缩写,它与fork()类似,但是设计用于创建新进程的方式不同。

vfork()fork()的区别主要在于 fork()操作可能会导致内存的复制。而在vfork()中,子进程共享父进程的地址空间。子进程会暂时阻塞父进程的运行,直到调用exec()exit()为止。由于子进程与父进程共享内存空间,所以对内存的修改会影响父进程,因此子进程通常需要立即调用exec()来替换自己的内存空间,或者直接调用exit()来结束自己的执行。

注意:

  • vfork()适用于需要在子进程中立即调用exec()来执行新程序的场景,因为子进程共享父进程的内存空间,所以对于子进程而言,任何内存修改都会影响到父进程,这样可以减少内存的复制和性能开销。

  • 一般来说,如果没有立即调用exec()exit(),而是在子进程中执行其他操作,可能会导致父进程和子进程的行为变得不可预测,因为它们共享相同的内存空间。

写时拷贝

写时拷贝(Copy-On-Write,简称COW)是一种用于资源管理的优化策略,广泛应用于操作系统中,尤其是在进程创建(如fork()系统调用)时。在没有写时拷贝技术之前,fork()调用会直接复制父进程的整个地址空间到子进程,这个过程不仅耗时,还会消耗大量的系统资源。写时拷贝技术的引入,显著优化了这一过程。

在使用写时拷贝技术时,fork()调用并不立即复制父进程的物理内存页面到子进程。相反,操作系统使父进程和子进程共享同一物理内存页面,页面的权限被设置为只读。如果父进程或子进程尝试写入这些共享页面,操作系统会捕捉到这一写操作尝试,并仅为执行写操作的进程复制被写的页面,在必要时才会进行数据复制。这种延迟复制的策略极大地提高了系统的效率和性能。

优点:

  • 减少不必要的数据复制
  • 提高效率和性能
  • 优化内存使用
  • 简化编程模型

进程状态

在Linux系统中,进程的状态是通过进程控制块中的状态字段来表示的。主要包括以下几种:

  • 运行(R, Running or Runnable): 这个状态意味着进程要么正在CPU上运行,要么在等待队列中准备运行。换句话说,这些进程是准备执行的。
  • 中断睡眠(S, Interruptible Sleep): 进程因等待某个条件而睡眠,如等待输入/输出操作完成。在这个状态下,进程会睡眠直到等待的事件发生,但可以被信号(signal)唤醒。
  • 不可中断睡眠(D, Uninterruptible Sleep): 这也是一种睡眠状态,但进程不能通过信号唤醒。这通常发生在进程等待某些硬件操作完成时,比如磁盘I/O。
  • 暂停(T, Stopped or Traced): 进程已经被停止,通常是因为接收到了停止信号。这个状态的进程可以通过接收SIGCONT信号重新进入运行状态。
  • 僵尸(Z, Zombie): 进程已经结束,但其父进程还没有通过调用wait()来回收其资源。在这个状态下,进程释放了除进程控制块之外的所有资源,等待父进程读取其退出状态。
  • 死亡(X, Dead): 这个状态比较少见,表示进程已经被完全销毁,但在某些情况下,可能会在进程列表中短暂看到。

在这里插入图片描述

僵尸进程

僵尸进程产生的主要原因是父进程没有及时处理子进程的退出状态。当一个子进程终止时,内核会向父进程发送一个信号,告知子进程已经退出,并且等待父进程调用 wait()waitpid() 来获取子进程的退出状态。如果父进程没有处理这个退出状态,子进程就会变成僵尸进程。

僵尸进程可能产生的一些原因包括:

  1. 父进程没有正确地调用 wait()waitpid() 函数来等待子进程的退出状态。 父进程可能忙于处理其他任务,或者没有正确处理子进程退出的情况,导致子进程变成僵尸进程。

  2. 父进程被阻塞,无法处理子进程的退出状态。 如果父进程正在执行一些阻塞操作,例如等待 I/O 完成,那么它可能无法及时处理子进程的退出状态。

僵尸进程的存在可能会对系统造成一些危害:

  1. 资源浪费: 僵尸进程在系统进程表中占用资源,虽然不再执行任何代码,但仍然占用一些系统资源,例如进程标识符(PID)等。

  2. 影响系统稳定性: 如果系统中存在大量的僵尸进程,可能会消耗系统的资源,并且可能影响系统的性能和稳定性。

  3. 影响进程管理: 如果系统中存在过多的僵尸进程,会使得进程管理变得困难,特别是在需要监控和管理系统进程的情况下。

为了避免僵尸进程的产生和危害,父进程应该在子进程终止后及时调用 wait()waitpid() 函数来等待子进程的退出状态,并确保对子进程进行适当的处理。这样可以及时释放子进程所占用的系统资源,并保持系统的稳定性和可靠性。

孤儿进程

孤儿进程是指其父进程先于它结束,由 init 进程(PID 为 1)接管的进程。在 Unix/Linux 系统中,每个进程都有一个父进程,当父进程退出或终止时,内核会将孤儿进程的父进程设置为 init 进程。

孤儿进程的产生可以由以下几种情况引起:

  1. 当一个父进程创建了一个子进程后,如果父进程先于子进程退出,并且子进程还在运行,那么子进程就会成为孤儿进程。
  2. 如果一个进程是由 init 进程直接启动的,而 init 进程不会退出,那么这个进程本身就是一个孤儿进程。

孤儿进程并不会被立即回收,而是会继续运行,直到它自己退出或被系统进程管理器接管。当孤儿进程退出时,它的资源会被释放,但是其进程号(PID)会一直保留在系统中,直到父进程调用 wait()waitpid() 来获取退出状态。

孤儿进程的存在并不会对系统造成太大的影响,但是如果大量孤儿进程堆积在系统中,会占用系统资源。

守护进程

守护进程(Daemon Process)是在后台运行的一种特殊类型的进程,通常在系统引导时启动,并且在系统关闭时终止。它们在操作系统启动时启动,通常不与任何控制终端关联。

守护进程通常用于执行系统服务或后台任务,它们独立于用户会话并在后台默默地执行工作。守护进程的特点包括:

  1. 没有控制终端: 守护进程通常不会与任何控制终端(如终端或控制台)关联,因此它们不接收或发送任何与终端相关的输入或输出。

  2. 独立于用户会话: 守护进程不受用户登录或注销的影响,它们在系统启动时启动,在系统关闭时终止。

  3. 后台运行: 守护进程在后台默默地执行任务,通常不会产生交互式的用户界面。

  4. 执行系统服务或后台任务: 守护进程通常用于执行系统服务,如网络服务、日志服务、定时任务等,或者执行后台任务,如定期备份、监控等。

  5. 通常以超级用户权限运行: 一些守护进程需要特殊的权限才能执行其任务,因此它们通常以超级用户(root)的身份运行。

编写守护进程的关键是将进程脱离控制终端,并且使之成为后台进程。通常涉及到以下几个步骤:

  1. 调用 fork() 创建子进程,然后父进程退出,使得子进程成为孤儿进程。
  2. 调用 setsid() 函数创建新的会话,并使进程成为会话组的首领,脱离控制终端。
  3. 改变当前工作目录,防止守护进程占用某个挂载点而导致其无法卸载。
  4. 关闭不需要的文件描述符,防止其在后续操作中产生问题。
  5. 执行守护进程的核心任务。

进程地址空间

是什么

Linux进程地址空间是操作系统为每个正在运行的进程分配的虚拟内存空间。它是进程所能访问的全部内存区域的抽象表示,包含了进程运行时所需的代码、数据、堆、栈等内容。

在这里插入图片描述

Linux进程地址空间通常被划分为以下几个主要部分:

  1. 代码段(Text Segment): 代码段存放着可执行程序的指令代码。在Linux中,这部分内存通常是只读的,以防止程序意外修改自身的指令内容。

  2. 数据段(Data Segment): 数据段存放着已初始化的全局变量和静态变量的内存空间。这些变量在程序开始时就已经分配了内存空间,并且可以在程序的整个生命周期中使用。

  3. 堆(Heap): 堆是动态分配内存的区域,程序可以在运行时通过调用 malloc()calloc()realloc() 等函数从堆中分配内存。堆的大小在程序运行过程中是动态变化的,取决于程序的动态内存分配和释放操作。

  4. 栈(Stack): 栈用于存储函数调用期间的局部变量、函数参数、返回地址等信息。每次函数调用时,都会在栈上分配一段内存空间,函数返回时则释放这段空间。栈的大小在程序启动时就确定了,并且通常比堆小得多。

  5. 内存映射区域(Memory-mapped Regions): 这部分内存用于存储程序加载的动态链接库、共享库、内存映射文件等内容。它们被映射到进程的地址空间中,使得程序可以直接访问这些内容。

  6. 其他: 除了以上主要的部分外,Linux进程地址空间还可能包括一些其他区域,例如进程环境变量、命令行参数、进程控制块等。

Linux进程地址空间的管理由操作系统内核负责,它通过虚拟内存管理来管理和分配进程的地址空间,以及实现内存保护和地址映射等功能。每个进程都拥有自己独立的地址空间,使得多个进程之间的内存访问彼此隔离,提高了系统的安全性和稳定性。

为什么

进程地址空间在操作系统中起着至关重要的作用,没有它会导致诸多问题:

  1. 内存隔离: 进程地址空间使得每个进程拥有独立的内存空间,进程之间的内存互相隔离。这种隔离确保了进程的安全性和稳定性,防止了进程之间的相互干扰和不受控制的内存访问。

  2. 内存保护: 进程地址空间允许操作系统实现内存保护机制,通过设置页面权限和地址空间布局,防止进程对其他进程的内存区域进行非法访问或修改。这有助于防止恶意软件攻击和进程崩溃。

  3. 资源管理: 进程地址空间使得操作系统可以更好地管理系统资源,包括内存、CPU 时间和文件描述符等。操作系统可以根据进程的需要动态调整地址空间的大小和布局,以优化系统性能和资源利用率。

  4. 动态内存分配: 进程地址空间允许程序在运行时动态地分配和释放内存,从而实现灵活的内存管理。程序可以根据需要动态调整堆和栈的大小,以适应不同的运行环境和内存需求。

  5. 共享内存和通信: 进程地址空间为进程间通信提供了基础,允许进程通过共享内存等机制进行数据交换和通信。这种通信方式在多进程和多线程编程中非常常见,可以提高程序的效率和并发性。

怎么做

当源代码经过编译、链接等处理后,生成了 ELF(Executable and Linkable Format)格式的可执行文件。当用户执行一个 ELF 格式的可执行文件时,操作系统会创建一个新的进程,并为其分配独立的进程地址空间。进程地址空间是操作系统为进程分配的虚拟内存空间,用于存放程序的代码、数据、堆、栈等内容。

ELF 文件是一种标准的可执行文件格式,在 Unix、Linux 和类 Unix 系统中广泛使用。它包含了程序的代码、数据、符号表、重定位表等信息。

ELF 格式可执行文件在进程地址空间中的运行过程如下:

  • 当用户执行一个 ELF 可执行文件时,操作系统会加载该文件到内存中,然后将其内容映射到新创建的进程地址空间中。
  • ELF 文件的代码段被映射到进程的代码段,数据段被映射到进程的数据段,全局变量和静态变量等被放置在数据段中。
  • 堆和栈被初始化并分配给进程,堆用于动态内存分配,栈用于函数调用和局部变量存储。
  • 进程的地址空间中还可能包括共享库、内存映射文件等内容,它们也被映射到进程的地址空间中。

由上就可以知道操作系统运行程序的步骤大概如下:

  1. 加载 ELF 文件:

    • 操作系统的程序加载器(如 Linux 上的 ld-linux.so)首先解析 ELF 文件头,确定程序入口点(entry point),代码(.text)段、数据(.data 和 .bss)段等必要信息。
    • 加载器将 ELF 文件中的各个段映射到进程的虚拟地址空间中。代码段通常是只读的,数据段可以是可写的。
  2. 地址空间映射:

    • ELF 文件中定义的虚拟地址在此步骤中被映射到进程的虚拟地址空间。这涉及到将程序的代码和数据加载到内存中的适当位置。
    • 对于动态链接的应用程序,加载器还负责解析和加载所有需要的共享库(.so 文件),并将它们映射到进程的地址空间中。
  3. 重定位:

    • ELF 文件可能需要重定位,以便调整代码和数据中的某些引用,使它们指向正确的地址。对于动态链接的应用程序,这也包括解析符号引用,将它们绑定到实际的内存地址。
  4. 初始化:

    • 在开始执行程序之前,操作系统或运行时环境可能需要执行一些初始化操作,例如初始化运行库、设置堆、处理环境变量和命令行参数等。
  5. 执行:

    • 一切准备就绪后,控制权被转移给程序的入口点(通常是一个名为 main 的函数)。此时,程序开始执行其代码。
    • 程序运行过程中,可以进行函数调用、内存分配、输入输出操作等。
  6. 终止:

    • 程序执行完毕后(例如 main 函数返回),或者调用退出(如 exit)函数,程序开始终止过程。
    • 在终止过程中,操作系统负责清理资源,关闭打开的文件描述符,释放内存等,最终结束进程。

整个过程是由操作系统的内核、程序加载器、运行时库共同协作完成的。这确保了程序能够被正确地加载、执行,并在执行完毕后,相关资源能够被妥善地释放。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/702121.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python实战:爬取小红书——采集笔记详情

上一篇文章发出后,有读者问能不能爬到小红书笔记详情数据,今天他来了。 Python实战:爬取小红书 一、先看效果 程序输入:在一个txt文件内粘贴要爬取的笔记链接,每行放1个链接。 程序输出:输出是一个所有笔记…

docker-compose 搭建laravel环境

laravel环境包含nginx,mysql,php7.4,redis 一、安装好docker后pull镜像 1.nginx镜像 docker pull nginx:latest单独启动容器 docker run --name nginx -p 80:80 -d nginx 2.php镜像 docker pull php:7.4-fpm3.mysql镜像 docker pull mysql:5.74.redis镜像 docker pull r…

zabbix3.4.6 源码安装

Step1: 下载 https://www.zabbix.com/download 选中一下。download Zabbix Sources PackageReleaseDateRelease NotesZabbix ManualDownloadZabbix 3.4Server, Proxy, Agent, GUI3.4.615 January, 2018 Download step2 :拷贝在redhat 6.3_X86_86(192…

UE蓝图 序列(Sequence)节点和源码

系列文章目录 UE蓝图 Get节点和源码 UE蓝图 Set节点和源码 UE蓝图 Cast节点和源码 UE蓝图 分支(Branch)节点和源码 UE蓝图 入口(FunctionEntry)节点和源码 UE蓝图 返回结果(FunctionResult)节点和源码 UE蓝图 函数调用(CallFunction)节点和源码 UE蓝图 函数调用(CallFunction)…

springboot215基于springboot技术的美食烹饪互动平台的设计与实现

美食烹饪互动平台的设计与实现 摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统美食信息管理难度大&…

MAC地址学习和老化

MAC地址学习过程 一般情况下,MAC地址表是设备根据收到的数据帧里的源MAC地址自动学习而建立的。 图1 MAC地址学习示意图 如图1,HostA向SwitchA发送数据时,SwitchA从数据帧中解析出源MAC地址(即HostA的MAC地址)和VLAN…

做接口测试的流程一般是怎么样的?UI功能6大流程、接口测试8大流程这些你真的全会了吗?

在讲接口流程测试之前,首先需要给大家申明下:接口测试对于测试人员而言,非常非常重要,懂功能测试接口测试,就能在企业中拿到一份非常不错的薪资。 这么重要的接口测试,一般也是面试笔试必问。为方便大家更…

C++ //练习 8.13 重写本节的电话号码程序,从一个命名文件而非cin读取数据。

C Primer(第5版) 练习 8.13 练习 8.13 重写本节的电话号码程序,从一个命名文件而非cin读取数据。 环境:Linux Ubuntu(云服务器) 工具:vim 代码块 /***************************************…

Unity(第四部)新手组件

暴力解释就是官方给你的功能;作用的对象上面如: 创建一个球体,给这个球体加上重力 所有物体都是一个空物体,加上一些组件才形成了所需要的GameObject。 这是一个空物体,在Scene场景中没有任何外在表现,因为…

公厕智慧化_智慧化的公厕

公厕智慧化是现代城市建设中的重要一环。通过信息化、数字化和智慧化技术手段,实现对公共厕所的高效管理和服务,不仅提升了城市环境质量,还改善了居民生活品质。智慧公厕的智慧化包括监测、管理、服务和设备的智慧化,利用先进科技…

1分钟带你学会Python的pass关键字和range函数

1.pass 关键字 pass关键字在 python 中没有任何实际意义,主要是用来完成占位的操作,保证语句的完整性 age int(input(请输入您的年龄:))if age > 18: pass # pass 在此处没有任何意义,只是占位 print(欢迎光临。。。…

常见的排序算法整理

1.冒泡排序 1.1 冒泡排序普通版 每次冒泡过程都是从数列的第一个元素开始,然后依次和剩余的元素进行比较,若小于相邻元素,则交换两者位置,同时将较大元素作为下一个比较的基准元素,继续将该元素与其相邻的元素进行比…

Spring 中 ApplicationContext 和 BeanFactory 的区别有哪些

先看一张类图: 区别: 1:包目录不同: spring-beans.jar 中 org.springframework.beans.factory.BeanFactory spring-context.jar 中 org.springframework.context.ApplicationContext 2:国际化: BeanFacto…

mysql的日志文件在哪?

阅读本文之前请参阅----MySQL 数据库安装教程详解(linux系统和windows系统) MySQL的日志文件通常包括错误日志、查询日志、慢查询日志和二进制日志等。这些日志文件的位置取决于MySQL的安装和配置。以下是一些常见的日志文件位置和如何找到它们&#xff…

PHP中的飞碟运算符、取反运算符、对比非ASCII字符串、对比浮点数操作

对比浮点数 在电脑里存储的浮点数可能会和输入的值有些许差异,比如输入的是10.0,但存储的是10.00001. 在比较两个浮点数是否相等时可以计算下两个数的差值,然后查看下两数之差是否小于可以接受的阈值,如果要求精度在小数点后5位的…

ubuntu 22.04LTS的一些使用心得

前言 笔者一直在折腾ubuntu作为开发的主力系统,尤其是最近微信和各种软件陆续支持Debian系列,很多软件都可以用了,当然开源的软件大部分是跨平台的,尤其是idea系列。 X11 OR Wayland 关于X11和wayland,笔者还是使用…

9.5K Star,又一款超棒开源轻量自动化运维平台

Hi,骚年,我是大 G,公众号「GitHub指北」会推荐 GitHub 上有趣有用的项目,一分钟 get 一个优秀的开源项目,挖掘开源的价值,欢迎关注。 一个好的运维平台就变得非常重要了,可以节省大量的人力和物…

ElasticSearch索引数据备份与恢复

索引数据备份 在磁盘创建备份目录并授权 # 创建备份目录 /home/esbackup # 授权 chmod 777 /home/esbackup修改配置文件elasticsearch.yml echo path.repo: ["/home/esbackup"] >> /etc/elasticsearch/elasticsearch.yml重启elasticsearch(我是docker创建的…

c++ Qt 网络连接

1、基础概念 1.1 TCP/UDP TCP 是一种面向连接的传输层协议,它能提供高可靠性通信(即数据无误、数据无丢失、 数据无失序、数据无重复到达的通信) 适用情况: 1.SN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议 2、适合于对传输质量要求较…

软件工程复习笔记

一、软件工程概述 软件 = 程序 + 数据 + 相关文档 软件危机(Software Crisis) 指由于落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重问题的现象。 软件工程三要素 方法、工具、过程 软件工程目标 在给定成本、进度的…