进程及进程地址空间

news2024/9/25 23:19:25

进程理解

概念:进程是程序的一个执行实例,其实启动一个程序(静态)本质就是启动了一个进程(动态),进程具有独立性。

用户角度:进程=代码+数据+内核数据结构(PCB结构体+页表+操作系统分配的地址空间)。

内核角度:承担分配系统资源的基本实体。

        Linux是可以同时加载多个程序的,即Linux是可能存在大量进程的,因此必须要对大量的进程进行管理,而管理的方式便是“先描述,再组织”。为了描述进程,每个进程都有一个属于自己的PCB结构体,全称process_control_block,也称进程控制块。在不同的操作系统中,PCB的具体名字是不同的,Linux中为struct task_struct{ };它会被加载到内存中,并且携带着进程的信息。

task_struct内容分类

        将进程的具体信息抽象成为task_struct之后,对进程的管理就变成了对进程PCB结构体链表的增删查改。操作系统和CPU运行某个进程的本质就是从运行队列中挑选一个task_struct来执行该进程对应的代码。

创建进程

        Linux中通过fork()系统调用从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。fork()之后要用if分流,子进程返回0,父进程返回子进程的pid,失败时返回-1。pid就是进程标识符。

fork常规用法

一个父进程希望复制自己,使父子进程同时执行不同的代码段。例如,父进程等待客户端请求,生成子 进程来处理请求。 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。

fork调用失败的原因

系统中有太多的进程

实际用户的进程数超过了限制

        进程调用fork,当控制转移到内核中的fork代码后,内核做如下几件事:

        1、分配新的内存块和内核数据结构给子进程。

        2、将父进程部分数据结构内容拷贝至子进程。

        3、添加子进程到系统进程列表当中。

        4、fork返回,开始调度器调度。

        fork之后,系统内多了一个进程,要给子进程创建对应的内核数据结构,必须子进程自己独有,因为进程具有独立性。理论上,子进程也要有自己的代码和数据,可是一般而言,创建子进程的并没有加载过程,因此,子进程只能“使用”父进程的代码和数据。具体“使用”的策略是代码部分为只读,对应数据部分为写时拷贝。

具体原因

1、当真正使用时再进行对应资源分配,是高效使用内存的一种表现。

2、操作系统无法在代码执行前预知哪些空间会被拷贝。

具体例子:

#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<iostream>
int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        std:: cout << "我是子进程" << "pid为: " << getpid() << std::endl;
    }
    else if(id < 0)
    {
        //创建子进程失败
        perror("fork");
        exit(-1);//退出码设置为-1;
    }
    else
    {
       //父进程
       waitpid(id, nullptr, 0);//等待子进程退出,父进程回收子进程资源 
       std:: cout << "我是父进程" << "pid为: " << getpid() << std::endl;
    }
    return 0;
}

        此处父进程和子进程的调度顺序并不是绝对的,而是要看操作系统的调度策略。

进程状态

概念:进程状态分为新建状态,运行状态,阻塞状态,挂起状态和退出状态。

        首先,操作系统管理的资源一定是各种各样的,不仅仅是CPU资源,还有诸如网卡,显卡,磁盘等其他设备,因此除了运行队列之外,系统中还存在其他进行管理资源等待与分配的队列。

 运行状态:并不仅仅是该进程正在运行就叫做运行态,而是task_struct在对应的运行队列中排队,这个task_struct对应的进程状态就叫做运行态。

阻塞状态:处于阻塞状态的进程,一定是处于某种资源未就绪的状态,因此等待非CPU资源就绪的进程所处的状态就称为阻塞状态。

挂起状态:内存快不足时,操作系统会执行一种策略,将长时间不执行的进程代码和数据换出到磁盘中,用来缓解内存使用紧张的问题。被换出的进程只有PCB在内存中。此时该进程的状态就称为挂起。

具体Linux下的进程状态

僵尸进程:进程已经退出,但是还不允许被操作系统释放,处于一个被检测的状态的进程称为僵尸进程。

具体例子:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        //创建子进程失败
        perror("fork error");
        return -1;
    }
    else if(id > 0)
    {
        //father process
        int cnt = 0;
        while(cnt < 10)
        {
            printf("我是父进程, pid:%d, ppid:%d\n", getpid(), getppid());
            ++cnt;
        }
    }
    else
    {
        //child process
        int cnt = 0;
        while(cnt < 5)
        {
            printf("我是子进程, pid:%d, ppid:%d\n", getpid(), getppid());
            ++cnt;
        }
    }
    return 0;
}

        上面的例子中,子进程先退出,父进程后退出,在子进程退出而父进程未退出的时间段内,该子进程为僵尸进程。

为什么会有僵尸进程的原因

        本质是为了维持该状态,以便于父进程结束后及时回收该系统资源,但维持该状态就意味着要维持该僵尸进程的PCB,虽然代码和数据可以被释放,但PCB不行,所以会存在系统资源层面的内存泄露问题。

        要解决僵尸进程的问题,要通过进程等待系列的系统接口wait和waitpid。

孤儿进程

概念:父进程提前退出,子进程并没有退出,此时的子进程称为孤儿进程。该孤儿进程会被1号进程领养,作为该进程的父进程来回收该子进程的资源,避免系统资源层面的内存泄露。1号进程就是bash。

具体例子:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        //子进程创建失败
    }
    else if(0 == id)
    {
        //child process
        int cnt = 0;
        while(cnt < 5)
        {
            printf("我是子进程  pid: %d, ppid:%d\n", getpid(), getppid());
            sleep(1);
            ++cnt;
        }
    }
    else
    {
        //father process
        int cnt = 0;
        while(cnt < 2)
        {
            printf("我是父进程  pid:%d, ppid:%d\n", getpid(), getppid());
            sleep(1);
            ++cnt;
        }
    }
    return 0;
}

上面例子中,父进程先退出,在父进程退出到子进程退出的时间段内,该子进程称为孤儿进程。

进程地址空间

概念:进程地址空间是操作系统为了管理实际内存而设计的一种数据结构,是一种虚拟地址。每个进程在被创建时,除了进程PCB之外,在合适的时候,操作系统也会为该进程申请对应的进程地址空间和页表,通过填写页表,维护虚拟地址和真实物理地址的关系。

设计进程地址空间的原因及好处

1、进程直接访问物理内存是不安全的,通过进程地址空间,凡是非法的访问或者映射,操作系统都会识别并终止该进程。有效的保护了物理内存和物理内存中的合法数据,因为地址空间和页表是操作系统创建和维护的,凡是向使用地址空间和页表进行映射,也一定会在操作系统的监管之下进行访问。

2、因为有地址空间的存在,因为有页表的映射存在,物理内存中可以对数据进行任意位置的加载,原本物理内存中的几乎所有数据和代码在内存中是乱序的,有了地址空间和页表后,在进程视角,所有的内存分布都可以是有序的,所以地址空间+页表的存在可以将内存分布有序化。

3、进程要访问的物理内存中的数据和代码,可能目前并没有在物理内存中,同样的,也可以让不同的进程映射到不同的物理内存,通过地址空间+页表的方式实现了进程的独立性。页表映射的时候,不仅仅可以映射物理内存,磁盘中的位置也是可以映射的。

4、完成了内存管理和进程管理模块的解耦合,本质上,因为地址空间的存在,上层申请空间其实是在地址空间上申请的,物理内存可以甚至一个字节都不给你,只有当真正进行对物理地址空间访问的时候,才执行内存的相关管理算法,帮你申请内存,构建页表映射关系,提高内存整体使用效率。

小问题

在fork后,返回值有两个,是因为两个进程分别return,子进程和父进程返回的值看似存到一个变量中,实际在页表映射时,映射的是不同的物理地址,也就是说,虚拟地址可以显示的一样,但实际上页表映射的物理空间是不一样的。

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

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

相关文章

mysql的DDL语言和DML语言

DDL语言&#xff1a; 操作数据库&#xff0c;表等&#xff08;创建&#xff0c;删除&#xff0c;修改&#xff09;&#xff1b; 操作数据库 1&#xff1a;查询 show databases 2:创建 创建数据库 create database 数据库名称 创建数据库&#xff0c;如果不存在就创建 crea…

【Qcom Camera】DumpDebugInfo分析

DumpDebugInfo&#xff1a; DumpDebugInfo主要包括Session::DumpDebugInfo、Pipeline::Dumpdebuginfo、Node::Dumpdebuginfo、DRQ::Dumpdebuginfo、Usecase::DumpDebugInfo log&#xff1a;Hit SOF threshold of [xx] consecutive frames CamX: [ERROR][CORE ] camxpip…

P8837 [传智杯 #3 决赛] 商店(贪心加双指针)

题目背景 思路解析:很经典的贪心问题,把物品按照从便宜到贵的顺序排好序,然后按照富贵程度排人,直接暴力会tle所以这里采用双指针. #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<string> using namesp…

AI-数学-高中-39空间向量-2空间向量法(法向量)

原作者视频&#xff1a;【空间向量】【一数辞典】2空间向量法&#xff08;重要&#xff09;_哔哩哔哩_bilibili 法向量&#xff08;高中阶段所有与面的关系&#xff0c;都可以通过法向量去证明和解答&#xff09;&#xff1a; 是空间解析几何的一个概念&#xff0c;垂直于平面…

Java转go,我用了12小时,10小时在解决环境问题

Part1 问题背景 作为一个资深的Java开发者&#xff0c;我深知面向对象的高级语言&#xff0c;语法是不用学的。需要的时候搜索就可以了&#xff0c;甚至可以用ChatGPT来写。 之前我做一个安全多因素校验服务。因为是临时服务&#xff0c;扩展性上基本没有要求&#xff0c;为了快…

AI检索增强生成引擎-RAGFlow-深度理解知识文档,提取真知灼见

&#x1f4a1; RAGFlow 是什么&#xff1f; RAGFlow是一款基于深度文档理解构建的开源RAG&#xff08;Retrieval-Augmented Generation&#xff09;引擎。RAGFlow个人可以为各种规模的企业及提供一套专业的RAG工作流程&#xff0c;结合针对用户群体的大语言模型&#xff08;LL…

玩转 AIGC!使用 SD-WebUI 实现从文本到图像转换

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 基于大家…

500道Python毕业设计题目推荐,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Quick Service Setup(快速服务设置)

Quick Service Setup界面使用户能够使用最少的参数快速配置和编辑简单的应用程序服务。Alteon自动为虚拟服务创建所需的对象(虚拟服务器、服务器组、真实服务器、SSL策略、FastView策略等)。通过快速服务设置&#xff0c;您可以配置HTTP, HTTPS&#xff0c;基本slb(第4层TCP或U…

BootstrapAdmin Net7:基于RBAC的后台管理框架,实现精细化权限管理与多站点单点登录

BootstrapAdmin Net7&#xff1a;基于RBAC的后台管理框架,实现精细化权限管理与多站点单点登录 摘要 随着企业信息化建设的不断深入&#xff0c;后台管理系统在企业运营中扮演着越来越重要的角色。本文介绍了一款基于RBAC&#xff08;Role-Based Access Control&#xff09;的…

海外媒体如何发布软文通稿

大舍传媒-带您了解海外发布新潮流 随着全球化的不断深入&#xff0c;越来越多的中国企业开始关注海外市场。为了在国际舞台上树立品牌形象&#xff0c;企业纷纷寻求与海外媒体合作&#xff0c;通过发布软文通稿的方式&#xff0c;传递正面信息&#xff0c;提升品牌知名度。作为…

算法导论 总结索引 | 第三部分 第十一章:散列表

1、动态集合结构&#xff0c;它至少要支持 INSERT、SEARCH 和 DELETE字典操作 散列表 是实现字典操作的 一种有效的数据结构。尽管 最坏情况下&#xff0c;散列表中 查找一个元素的时间 与链表中 查找的时间相同&#xff0c;达到了 Θ(n)。在实际应用中&#xff0c;散列表的性…

制造业降本,为什么要关注流程挖掘?

不同于传统制造,智能制造企业数字化启动早、程度高,却总因“集成陷阱”无法摆脱业财协同差的问题。长期的“治标不治本”,导致超支、违规、资金分配不合理等问题仍藏于每个任务流中,甚至直接影响营运现金流的健康度。 《从流程挖掘到降本增收——智能制造企业支出洞察》报告,基…

实验2 NFS部署和配置

一、实训目的 1.了解NFS基本概念 2.实现NFS的配置和部署 二、实训准备 1.准备一台能够安装OpenStack的实验用计算机&#xff0c;建议使用VMware虚拟机。 2.该计算机应安装CentOS 7&#xff0c;建议采用CentOS 7.8版本。 3.准备两台虚拟机机&#xff08;客户机和服务器机&…

NTLM认证

文章目录 1.概念(1) 本地认证(2) SAM(3) NTLM Hash(4) NTLM 和 NTLM Hash(5) NTLM v2 1.概念 (1) 本地认证 Windows不存储用户的明文密码&#xff0c;它会将用户的明文密码经过加密后存储在 SAM (Security Account Manager Database&#xff0c;安全账号管理数据库)中。 (2)…

短视频素材哪里找?8个视频素材库免费下载无水印

是不是想要拓宽你的视频素材资源库&#xff0c;探索更多能够为你的视频项目注入新鲜血液的网站。这一次&#xff0c;我们将介绍一系列全球精选的视频素材网站&#xff0c;每一个都能为你的创作带来不同的视觉享受和灵感启发。 1. 蛙学府&#xff08;中国&#xff09; 提供广泛…

Docker② —— Cgroups详解

1. 概述 Cgroups 的全称是control groups&#xff0c;cgroups为每种可以控制的资源定义了一个子系统。Cgroups分为三个部分&#xff1a; cgroup 本身&#xff1a;对进程进行分组hierarchy&#xff1a;将 cgroup 形成树形结构subsystem&#xff1a;真正起到限制作用的部组件 cp…

从底层分析并详解SpringAOP底层实现

首先分析AOP的实现 首先切面&#xff08;Advisor&#xff09;由通知(Advice)和切点(Pointcut)组成 包括前置通知后置通知等等最终都会被转化为实现 MethodInterceptor 接口的环绕通知 先看一段代码了解一下是aop是怎么运作的 首先定义了两个类实现了MethodInterceptor接口&…

OpenCV与AI深度学习 | OpenCV如何读取仪表中的指针刻度

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;OpenCV如何读取仪表中的指针刻度 最近遇到一个问题&#xff0c;如何读取仪表中的指针指向的刻度。 解决方法有多种&#xff0c;比如&#xff…

67条tips实战案例渗透测试大佬的技巧总结

67条tips实战案例渗透测试大佬的技巧总结。 Tips 1. 手动端口探测 nmap的-sV可以探测出服务版本&#xff0c;但有些情况下必须手动探测去验证 使用Wireshark获取响应包未免大材小用&#xff0c;可通过nc简单判断 eg. 对于8001端口&#xff0c;nc连接上去&#xff0c;随便输…