Linux的进程概念

目录

1、冯诺依曼体系结构

2、操作系统(Operating System)

2.1 基本概念

2.2 目的

3、Linux的进程

3.1 基本概念

3.1.1 PCB

3.1.2 struct task_struct

3.1.3 进程的定义

3.2 基本操作

3.2.1 查看进程

3.2.2 初识fork

3.3 进程状态

3.3.1 操作系统的进程状态

3.3.2 Linux的进程状态

3.4 进程优先级

3.4.1 基本概念

3.4.2 PRI&&NI

3.4.3 竞争&&独立&&并行&&并发

3.5 进程切换

3.6 Linux2.6内核进程O(1)调度队列

4、Linux的环境变量

4.1 基本概念

4.2 常见的环境变量

4.3 环境变量的相关命令

4.3.1 查看环境变量

4.3.2 修改环境变量

4.3.3 删除环境变量

4.4 环境变量的特点

5、Linux的进程虚拟地址空间

5.1 程序地址空间

5.2 问题抛出

5.3 进程虚拟地址空间和分页机制

5.4 虚拟地址空间和分页机制的作用

5.5 拓展


1、冯诺依曼体系结构

  • 输入设备:键盘,鼠标,网卡,磁盘等。
  • 输入设备:显示器,网卡,磁盘等。
  • 存储器:即内存
  • CPU:简单来说,是中央处理器(运算器+控制器)。

注意:

  • 输入输出设备的传输效率低,但是,让输入输出的设备的传输效率变高,成本太高,所以出现内存,即效率与成本之间的平衡,才普及了电脑。
  • 程序的运行需要CPU,而CPU只能访问内存,所以程序必须加载到内存中
  • 数据流动的本质多台冯诺依曼体系结构的交互

2、操作系统(Operating System)

2.1 基本概念

操作系统包括:

  • 内核(进程管理,内存管理,文件管理,驱动管理)
  • 其他程序(例如函数库,shell程序等等)

2.2 目的

操作系统,是一款进行 软硬件 管理 的软件。管理:先描述(类),再组织(数据结构)。

sysrem call(系统调用),驱动程序,都是为了屏蔽底层细节,外部实现统一。安全且方便。

  • 系统调用封装内核 → 对应用程序统一。

  • 驱动程序封装硬件 → 对操作系统统一。

3、Linux的进程

3.1 基本概念

3.1.1 PCB

PCB(Process Control Block),进程控制块,一种类型,Linux中的PCB为:struct task_struct

3.1.2 struct task_struct

内容分类(后续会详细介绍)

  • 标识符(PID):描述本进程的唯一标识符,用于区分其他进程。
  • 状态:任务状态,包括退出代码、退出信号等。
  • 优先级:相对于其他进程的优先级。
  • 程序计数器:程序中即将被执行的下一条指令的地址。
  • 内存指针:包括程序代码和进程相关数据的指针,以及与其他进程共享的内存块指针。
  • 上下文数据:进程执行时处理器的寄存器中的数据(例如:CPU 寄存器状态,需附图说明)。
  • I/O 状态信息:包括未完成的 I/O 请求、分配给进程的 I/O 设备,以及进程使用的文件列表。
  • 记账信息:可能包括处理器占用时间、时钟周期总和、时间限制、计账号等。
  • 其他信息:与进程相关的其他数据。

在 Linux 内核中,所有进程均通过 struct task_struct 结构体描述,并以双向链表的形式(即队列)组织和管理。

3.1.3 进程的定义

进程 = 内核数据结构对象(PCB)+代码和数据

进程的管理,就是对数据结构的增删改查

3.2 基本操作

3.2.1 查看进程

1. 通过 /proc 文件系统查看进程信息

  • /proc 是一个虚拟文件系统,提供内核和进程信息的实时访问。

  • 每个进程的信息存储在 /proc/[PID]/ 目录下,例如:

ls /proc/1/    # 查看 PID=1 的进程信息(通常是 init/systemd)

2. top动态查看进程状态(CPU、内存占用等)

top  # 默认动态显示所有进程(按 CPU 占用排序)
top -p PID1,PID2,PID3  # 只监控指定 PID 的进程
top -u username  # 只显示某用户的进程

交互命令(在 top 运行时使用)

  • k → 结束指定 PID 的进程(输入 PID 后回车)。

  • M → 按内存占用排序。

  • P → 按 CPU 占用排序(默认)。

  • q → 退出 top 。 

3. ps静态查看进程列表

ps aux  # 适用于查看所有进程的资源占用,进程状态等
ps -l PID # 适用于查看进程的父子关系,进程优先级等

注意:

  • 可以配合grep进行搜索
  • ;&&可以同时执行多条命令
  • 命令本身也是进程。

4.  通过系统调用,获取进程标识符(PID & PPID)

  • getpid():获取当前进程的 PID。

  • getppid():获取当前进程的父进程 PPID。

如:

#include <stdio.h>
#include <unistd.h>int main() {printf("PID: %d\n", getpid());   // 当前进程 IDprintf("PPID: %d\n", getppid()); // 父进程 IDreturn 0;
}
3.2.2 初识fork

通过fork(系统调用),创建子进程。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{int ret = fork();printf("hello proc : %d!, ret: %d\n", getpid(), ret);sleep(1);return 0;
}

 

  • 两个返回值,对父进程返回子进程的PID,对子进程返回0。因为父:子 = 1:N,父进程需要区分子进程,而子进程能通过PPID找到父进程。所以可以if,让父子进程执行不同的语句
  • fork() 创建子进程后,父子进程从 fork() 返回处继续执行注意:子进程不会执行fork()之前的代码。

  • 父子进程尝试修改数据,会发生写时拷贝,重新拷贝一份数据。所以父子进程独立运行

3.3 进程状态

3.3.1 操作系统的进程状态

以上可以分为三类:

  • 运行:PCB对象在调度队列中,正在运行(运行)或准备运行(创建+就绪)。
  • 阻塞等待某种设备或资源就绪,PCB对象进入设备队列或资源队列。
  • 挂起内存不足,将进程代码和数据放到磁盘中,进程是运行状态就是就绪挂起,进程是阻塞状态就是阻塞挂起。

注意:

  • 一个CPU,一个调度队列
  • PCB对象,可以同时在不同的数据结构中,即可以在不同的队列中

  • 进程的状态,就是PCB对象在不同队列之间的流动,本质是数据结构的增删改查。 
3.3.2 Linux的进程状态
/** The task state array is a "bitmap" of reasons to sleep.* "Running" is 0, other states can be combined via bit tests.*/
static const char *const task_state_array[] = {"R (running)",      /* 0  - 运行中或就绪       */"S (sleeping)",     /* 1  - 可中断睡眠(等待事件)*/"D (disk sleep)",   /* 2  - 不可中断睡眠(通常等待I/O)*/"T (stopped)",      /* 4  - 被信号暂停(如SIGSTOP)*/"t (tracing stop)", /* 8  - 被调试器跟踪暂停    */"X (dead)",         /* 16 - 完全终止(不会出现在任务列表)*/"Z (zombie)",       /* 32 - 僵尸进程(已终止但未回收)*/
};
  • R运行中就绪(进程一创建,就进入就绪状态)。
  • S可中断休眠(浅睡眠,一种阻塞),能被操作系统杀死。
  • D不可中断休眠(深睡眠,一种阻塞),不能被操作系统杀死。
  • T暂停,如:Ctrl+z。
  • t暂停,如:debug的断点。
  • X死亡进程结束
  • Z僵尸子进程退出父进程需要获取子进程退出前的信息(即子进程PCB对象里面的信息,其指向的代码和数据已被释放),并释放子进程的PCB对象,如果父进程没有获取子进程退出前的信息,那么子进程被称为"僵尸进程",其PCB对象将会一直存在,造成内存泄漏。如果父进程先结束,其子进程称为"孤儿进程",会被1号进程"领养",不会成为"僵尸进程"。

注意:

阻塞是进程的 正常状态(因等待资源主动暂停),而 饥饿是 异常现象(可能是一直阻塞,或进程可能无需等待资源,但因调度问题无法运行等)

3.4 进程优先级

3.4.1 基本概念

进程得到CPU资源先后顺序

注意:

  • 优先级是一种数字值越低优先级越高
  • 优先级能得到某种资源(只是先后问题),权限能否得到某种资源
  • Linux,基于时间片的分时操作系统,要考虑公平性,所以优先级变化不大
3.4.2 PRI&&NI
  • PRI:进程的优先级,默认80。
  • NI:nice值,进程优先级的修正数据,默认0。范围是[-20,19]

注意:

  • 进程真实的优先级PRI = 80 + NI。所以优先级的范围是[60,99]。保证公平性。
  • NI 的存在 是为了在 灵活性(用户态调整)和 稳定性(内核控制)之间取得平衡。

3.4.3 竞争&&独立&&并行&&并发
  • 竞争:系统中进程数量远多于 CPU 资源(如单核 CPU 只能同时运行 1 个进程),因此进程之间需要竞争 CPU 时间片、内存、I/O 等资源。通过 优先级(Priority) 或 调度算法(如时间片轮转)来合理分配资源,确保高优先级或关键任务能优先执行。
  • 独立:每个进程拥有独立的地址空间、文件描述符、寄存器状态等资源,一个进程崩溃不会直接影响其他进程
  • 并行多个进程在 多个 CPU/核心上真正同时运行(物理层面的同时执行)。
  • 并发多个进程在 单个 CPU 上通过快速切换(时间片轮转) 模拟“同时运行”的效果(逻辑层面的交替执行)。

3.5 进程切换

CPU上下文切换(Context Switch),实际上是任务切换,或CPU寄存器的切换

流程:

  1. 保存现场
    当多任务操作系统决定切换到另一个任务时,首先将当前运行任务的CPU寄存器状态完整保存到该任务的私有堆栈中。

  2. 恢复现场
    从待运行任务的堆栈中加载其之前保存的寄存器状态到CPU。

  3. 切换执行
    CPU开始执行新任务的指令流。

注意:

  • 进程在一个时间片内占用CPU,不会一直占用。
  • 进程切换本质保存和恢复 进程硬件上下文的数据(即CPU寄存器的状态)。 

3.6 Linux2.6内核进程O(1)调度队列

  • 对于active队列,先看nr_active,有没有进程,再通过bitmap[5],按照优先级,快速定位队列,最后挑队首的进程,执行。
  • 进程执行完一个时间片,进入expired队列(防止高优先级进程执行完一个时间片,又插队)。当active队列为空时,swap(&active,&expired),交换两个指针,继续调度active队列。
  • 新来一个进程,如果放到expired队列,就是就绪状态,如果放到active队列,也是就绪状态,但是"插队"了。
  • 如果active中的进程,更改NI(nice值),即更改优先级,因为麻烦,所以执行完一个时间片后,进入过期队列时,再更新优先级。

4、Linux的环境变量

4.1 基本概念

环境变量是操作系统中用于指定运行环境参数的键值对(KEY=VALUE)。

KEY环境变量的名字VALUE环境变量的内容

4.2 常见的环境变量

4.3 环境变量的相关命令

4.3.1 查看环境变量

命令行:

  • env:显示当前进程 所有的环境变量
  • echo $环境变量名字:显示环境变量的内容
  • set:显示当前进程 所有的变量。如:直接i=10或i,定义本地变量i。

系统调用:

  • int main(int argc,char* argv[ ],char* env[ ]){ return 0;},argv是命令行输入的命令字符串数组(以空格为分隔符,将命令分成若干个字符串,数组以NULL结尾),argcargv数组元素的个数env该进程 环境变量的字符串数组(环境变量放在字符串里,数组以NULL结尾)。
  • getenv(),在当前进程根据环境变量的名字获取环境变量的内容
  • 全局变量environ(环境变量字符串数组,数组以NULL结尾),必须先extern char** environ;声明,再使用。
4.3.2 修改环境变量
  • 环境变量名=$环境变量名:内容给环境变量加内容。如:PATH=$PATH:/home/Lzc/test。
  • export 变量名=“值”新增环境变量

注意:

以上关闭终端,重新登录,就会失效。想要永久生效,就要更改配置文件(~/.bashrc或~/.bash_profile),因为bash每次都是拷贝配置文件的内容。

4.3.3 删除环境变量
  • unset 变量名清除变量,本地变量和环境变量都可以。

4.4 环境变量的特点

  • 新创建的子进程会继承父进程的环境变量(全局性)。进程相互独立,所以环境变量也独立,互不影响。
  • 本地变量不会被新创建的子进程继承

5、Linux的进程虚拟地址空间

5.1 程序地址空间

以32位机器为例:

5.2 问题抛出

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>int g_val = 0;  // 全局变量,初始化为0int main() {pid_t id = fork();  // 创建子进程if (id < 0) {       // fork失败perror("fork");return 0;}else if (id == 0) { // 子进程分支g_val = 100;    // 子进程修改全局变量printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);} else {              // 父进程分支sleep(3);       // 父进程休眠3秒,确保子进程先执行printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);}sleep(1);           // 防止父进程或子进程提前终止return 0;
}

为什么地址一样,内容却不一样?  

说明:

  • 地址绝对不是物理地址
  • 在Linux系统下,这种地址称为**虚拟地址**。  
  • 我们用C/C++语言看到的地址都是虚拟地址,物理地址对用户完全不可见,由操作系统统一管理。  

5.3 进程虚拟地址空间和分页机制

所以,程序地址空间,准确来说是,进程虚拟地址空间。

首先,一个进程,一个虚拟地址空间。 

struct task_struct {/*...*/struct mm_struct *mm;        // 指向进程用户空间虚拟地址空间描述符// - 对普通用户进程:指向其虚拟地址空间的用户空间部分// - 对内核线程:NULL(因内核线程无独立用户空间)struct mm_struct *active_mm; // 内核线程使用的替代mm字段// - 内核线程的mm为NULL时,可借用其他进程的地址空间// - 所有进程的内核空间映射相同,故内核线程可复用/*...*/
};// 1.当虚拟区较少时采取单链表,由mmap指针指向这个链表;
// 2.当虚拟区间多时采取红⿊树进⾏管理,由mm_rb指向这棵树。
struct mm_struct {/*...*/struct vm_area_struct *mmap;    // 虚拟内存区域(VMA)链表头struct rb_root mm_rb;           // VMA红黑树根节点(加速查找)unsigned long task_size;        // 用户虚拟地址空间大小/* 各段地址边界 */unsigned long start_code, end_code;    // 代码段起止unsigned long start_data, end_data;    // 数据段起止unsigned long start_brk, brk;          // 堆段起止unsigned long start_stack;              // 栈起始地址unsigned long arg_start, arg_end;      // 命令行参数段unsigned long env_start, env_end;      // 环境变量段/*...*/
};struct vm_area_struct {unsigned long vm_start;         // 虚拟内存区域起始地址unsigned long vm_end;           // 虚拟内存区域结束地址/* 链表与树结构 */struct vm_area_struct *vm_next, *vm_prev;  // 双向链表指针struct rb_node vm_rb;                      // 红黑树节点unsigned long rb_subtree_gap;/* 关联的地址空间 */struct mm_struct *vm_mm;        // 所属的mm_struct/* 权限与标志 */pgprot_t vm_page_prot;          // 访问权限(读/写/执行)unsigned long vm_flags;         // 区域标志(如VM_READ|VM_WRITE)/* 共享与反向映射 */struct {struct rb_node rb;unsigned long rb_subtree_last;} shared;struct list_head anon_vma_chain;struct anon_vma *anon_vma;/* 操作方法与文件映射 */const struct vm_operations_struct *vm_ops;  // 区域操作函数集unsigned long vm_pgoff;         // 文件映射偏移量(以页为单位)struct file *vm_file;           // 映射的文件指针(若为文件映射)void *vm_private_data;          // 驱动私有数据/* 其他配置 */atomic_long_t swap_readahead_info;
#ifdef CONFIG_NUMAstruct mempolicy *vm_policy;    // NUMA内存策略
#endifstruct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

如图所示:

 一个进程,一个页表,进行虚拟地址和物理地址的映射。

将物理地址转化为虚拟地址,提供给用户使用。 

5.4 虚拟地址空间和分页机制的作用

  • 将地址,"无序"变"有序"。
  • 地址转化的过程中,可以对操作进行合法判定,进而保护物理内存(根据权限)。
  • 进程管理内存管理在一定程度上解耦合

5.5 拓展

  • 可以不加载代码和数据到物理内存,只有struct task_struct,struct mm_struct,页表,需要访问时,“缺页中断”,再加载。所以创建进程,先有struct task_struct,struct mm_struct等,再有代码和数据。
  • 当物理内存不足时,对于阻塞的进程,通过页表换出物理地址(释放内存),变为阻塞挂起,腾出内存空间。

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

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

相关文章

export和import的书写方式

一、导出模块&#xff08;export&#xff09; 1. 命名导出&#xff08;Named Exports&#xff09; // math.js export const PI 3.14159; // 导出单个常量 export function sum(a, b) { return a b; } // 导出单个函数 export class Calculator { /* ..…

HOW - 结合 AI 进行 Tailwind 样式开发

文章目录 情况 1&#xff1a;使用 Tailwind CSS 与手写传统 CSS 的开发效率对比情况 2&#xff1a;AI Tailwind 自动生成 UI 的效率如何&#xff1f;总结 在 WHAT - Tailwind 样式方案&#xff08;不写任何自定义样式&#xff09; 中我们已经简单介绍过 Tailwind。今天主要认识…

java面试每日一背 day1

1.什么是缓存穿透 缓存穿透是指查询一个数据库中根本不存在的数据&#xff0c;导致这个查询请求绕过缓存直接访问数据库的情况。这种情况如果频繁发生&#xff0c;会对数据库造成不必要的压力。 典型特征&#xff1a; &#xff08;1&#xff09;查询的数据在数据库和缓存中都…

ngx_http_realip_module 模块概述

一、使用场景 日志记录 记录真实客户端 IP 而非反向代理的 IP&#xff0c;有助于流量分析和安全审计。访问控制 基于真实 IP 实现防火墙规则&#xff08;allow/deny&#xff09;或限流&#xff0c;而非误将上游 IP 视为客户端。GeoIP、WAF、限速等功能 模块化的上游真实 IP 支…

实战5:个性化数字艺术生成与销售

盈利思路 数字艺术销售&#xff1a; 平台销售&#xff1a;将生成的数字艺术作品上传到像OpenSea、Foundation等NFT平台进行售卖。每一件独特的艺术品可以通过NFT技术保证其唯一性&#xff0c;吸引收藏家和投资者。 定价策略&#xff1a;根据作品的复杂度、创意性以及市场需求来…

游戏引擎学习第303天:尝试分开对Y轴和Z轴进行排序

成为我们自己的代码精灵α 所以现在应该可以正常使用了。不过&#xff0c;这两周我们没办法继续处理代码里的问题&#xff0c;而之前留在代码里的那个问题依然存在&#xff0c;没有人神奇地帮我们修复&#xff0c;这让人挺无奈的。其实我们都希望有个神奇的“代码仙子”&#…

InetAddress 类详解

InetAddress 类详解 一、核心作用 封装 IP 地址&#xff1a;同时支持 IPv4 和 IPv6 地址域名解析&#xff1a;将域名转换为 IP 地址&#xff08;DNS 查询&#xff09;地址验证&#xff1a;检查网络地址的有效性无构造方法&#xff1a;通过静态工厂方法获取实例 二、核心方法 …

spring cloud alibaba-Geteway详解

spring cloud alibaba-Gateway详解 Gateway介绍 在 Spring Cloud Alibaba 生态系统中&#xff0c;Gateway 是一个非常重要的组件&#xff0c;用于构建微服务架构中的网关服务。它基于 Spring Cloud Gateway 进行扩展和优化&#xff0c;提供了更强大的功能和更好的性能。 Gat…

iOS 直播技术及优化

iOS直播技术的实现和优化涉及多个技术环节&#xff0c;需结合协议选择、编解码方案、播放器技术及性能调优等多方面。 一、核心技术实现 协议选择与传输优化 HLS&#xff08;HTTP Live Streaming&#xff09;&#xff1a;苹果官方推荐&#xff0c;基于HTTP分片传输&#xff0c…

目标检测135个前沿算法模型汇总(附源码)!

目标检测是计算机视觉核心方向之一&#xff0c;也是发论文的热门领域&#xff01; 近来不仅YOLO算法迎来了新突破&#xff0c;迭代出YOLOv12&#xff01;Mamba、大模型等新技术的发展&#xff0c;也给该领域注入了全新的力量&#xff0c;取得了诸多显著成果。比如性能飙升82.3…

期刊采编系统安装升级错误

我们以ojs系统为例&#xff1a; PHP Fatal error: Uncaught Error: Call to a member function getId() on null in /esci/data/html/classes/install/Upgrade.inc.php:1019 Stacktrace: #0 /esci/data/html/lib/pkp/classes/install/Installer.inc.php(415): Upgrade->con…

浅谈无服务器WebSocket的优势

实际上&#xff0c;一个实用的解决方案是将构建业务关键型实时平台的复杂性卸载到专门的云服务中。 完全托管的无服务器 WebSocket 解决方案为事件驱动的消息传递提供了基础结构;它使底层基础设施成为一种商品。客户端使用提供程序服务发送/接收低延迟消息&#xff0c;并专注于…

Python数据可视化高级实战之二——热力图绘制探究

目录 一、热力图的作用 二、热力图反映的信息类型 三、热力图的典型应用场景 1. 地球信息系统 (GIS) 2. 城市交通分析 3. 市场分析 4. 用户行为分析 5. 网络流量分析 6. 传染病传播分析 7. 社交媒体舆情分析 四、Python 绘制热力图的关键技术要点 1. 数据预处理 2. 颜色选择与渐…

配电网运行状态综合评估方法研究

1评估指标体系的构建 [1]冷华,童莹,李欣然,等.配电网运行状态综合评估方法研究[J].电力系统保护与控制,2017,45(01):53-59. 1.1评估范围 图1为配电系统组成示意图&#xff0c;其中A、B、C分别表示高、中、低压配电系统。高压配变(也称主变)将35kV或110kV的电压降到10kV&#…

Docker安装MinIO对象存储中间件

MinIO 是一个高性能、分布式的对象存储系统&#xff0c;兼容 Amazon S3 云存储服务协议&#xff0c;广泛应用于企业存储、大数据、机器学习和容器化应用等领域。以下是详细介绍&#xff1a; 核心特点 兼容 S3 API &#xff1a;全面兼容 Amazon S3 API&#xff0c;这意味着使用…

HTML回顾

html全称:HyperText Markup Language(超文本标记语言) 注重标签语义,而不是默认效果 规则 块级元素包括: marquee、div等 行内元素包括: span、input等 规则1:块级元素中能写:行内元素、块级元素(几乎什么都能写) 规则2:行级元素中能写:行内元素,但不能写:块…

JAVA Spring MVC+Mybatis Spring MVC的工作流程*,多表连查

目录 注解总结 将传送到客户端的数据转成json数据 **描述一下Spring MVC的工作流程** 1。属性赋值 BeanUtils.copyProperties(addUserDTO,user); 添加依赖&#xff1a; spring web、mybatis framework、mysql driver Controller和ResponseBody优化 直接改成RestControl…

H2数据库中一条insert语句到生成java对象到数据写入磁盘的完整步骤

H2 数据库将 SQL 语句转换为磁盘存储的全过程可以分为以下 8 个关键步骤&#xff0c;我们以 INSERT INTO users (id, name) VALUES (1, Alice) 为例详细说明&#xff1a; 1. SQL 解析与语法树生成 词法分析&#xff1a;拆分语句为 INSERT、INTO、users 等 Token语法分析&#…

重磅升级!Google Play商店改版上线

5 月 21 日消息&#xff0c;Android Headline 今天&#xff08;5 月 21 日&#xff09;发布博文&#xff0c;报道称在 2025 年 I/O 开发者大会上&#xff0c;谷歌宣布更新 Google Play 应用商店&#xff0c;在优化用户体验的同时&#xff0c;提升开发者收益。 本次更新中&…

Docker面试题(1)

什么是Docker 一个容器化平台 形式是容器 将你的应用程序及所有依赖项打包在一起 确保应用程序在任何环境中无缝运行 什么是Docker镜像 Docker镜像是Docker容器的源代码 用于创建容器 使用build命令创建镜像 什么是 Docker容器 包括应用程序及所有的依赖项 作为操作系统的独立进…