赞
踩
虚拟地址空间
:虚拟内存将物理内存抽象为地址空间,每个进程都有各自地址空间。地址空间中页被映射到物理内存,地址空间的页并不需要全部在物理内存中,当使用到一个没有在物理内存的页时,执行页面置换算法,将该页置换到内存中。
虚拟地址空间的大小也由操作系统决定,32位的操作系统虚拟地址空间的大小为 2^32 字节,也就是4G,64位的操作系统虚拟地址空间大小为2 ^64 字节。
从操作系统层级上看,虚拟地址空间主要分为两个部分内核区和用户区。
内核空间在3-4G在今后陪你过,驻留在内存中,是操作系统的一部分。系统中所有进程对应的虚拟地址空间的内核区都会映射到同一块物理内存上(系统内核只有一个)。
Linux中一切都是文件,需要操作文件描述符进行读写操作。
Linux下进程启动就会得到一个对应的虚拟地址空间,进程控制块PCB中包含一个文件描述符表,用于存储文件描述符。
open/close 可以打开关闭文件,open还可以创建新的文件。
read 函数用于读取文件内部数据,在通过 open 打开文件的时候需要指定读权限。
write 函数用于将数据写入到文件内部,在通过 open 打开文件的时候需要指定写权限。
系统函数 lseek 的功能是比较强大的, 我们既可以通过这个函数移动文件指针, 也可以通过这个函数进行文件的拓展。
file命令可以查看文件信息。
stat命令显示文件或目录的详细属性信息包括文件系统状态,比ls命令输出的信息更详细。
dup函数的作用是复制文件描述符,这样就有多个文件描述符可以指向同一个文件了。可以在进程中创建多个对同一文件的引用,可以对文件进行读取写入等操作。
dup2() 函数是 dup() 函数的加强版,基于dup2() 既可以进行文件描述符的复制, 也可以进行文件描述符的重定向。文件描述符重定向就是改变已经分配的文件描述符关联的磁盘文件。
fcntl() 是一个变参函数, 并且是多功能函数,可以通过这个函数实现文件描述符的复制和获取/设置已打开的文件属性。
opendir(), readdir(), closedir()。 readdir() 函数遍历目录中的文件信息。
scandir()函数进行目录的遍历(只遍历指定目录,不进入到子目录中进行递归遍历)。
文件同步
:Linux中,文件系统通常使用缓存区来提高文件读写性能,当程序对文件进行读写操作时,数据首先会被写入到内核的缓冲区中,而不是直接写入磁盘,这样可以减少磁盘IO的次数,提高文件读写的效率。但是如果出现意外崩溃或断电,还未写入磁盘的数据将会丢失,导致数据的不一致性或丢失,这时候就需要用文件同步来确保数据的持久性和一致性。
文件同步需要用到的函数:
fsync:单个文件,同步数据,同步元数据(文件加上属性,如时间,大小等)
fdatasync:单个文件,同步数据,不同步元数据
sync:所有文件,同步数据,同步元数据
文本文件和二进制文件
:文本文件按照ASCII码编码,二进制文件按照十六进制编码。二进制文件比较稳定,不容易出错。
fopen : 标准IO打开文件。
fread:标准IO读取二进制文件。
fwrite:标准IO写二进制文件。
缓存
标准IO(fread,fwrite)引入了缓存的概念,为了减少系统调用,提高IO性能。标准IO比文件IO多了一个缓存的流程。
全缓存:数据量达到一定大小(4096字节)或遇到文件结束符时,缓冲区被刷新,数据才会被写入到目标设备(如终端或文件)。当打开文件后,如果文件与终端设备无关,则默认是全缓冲模式。
行缓存:包含换行符时会立即刷新。
无缓存:每次机械能IO操作时,都会立即刷新。
并行和并发
CPU在某个时间节点只能处理一个任务,但是操作系统都支持多任务的,CPU会给每个进程被分配一个时间段,进程得到这个时间片之后才可以运行,使各个程序从表面上看是同时进行的。如果在时间片结束时进程还在运行,CPU的使用权将被收回,该进程将会被中断挂起等待下一个时间片。如果进程在时间片结束前阻塞或结束,则CPU当即进行切换,这样就可以避免CPU资源的浪费。
在我们使用的计算机中启动的多个程序,从宏观上看是同时运行的,从微观上看由于CPU一次只能处理一个进程,所有它们是轮流执行的,只不过切换速度太快,我们感觉不到罢了,因此CPU的核数越多计算机的处理效率越高。
并发:并发的同时进行是一个假象,针对一个硬件资源,通过计算机CPU时间片的快速切换,使得程序表面看起来像是一起执行的。
并行:多进程同时运行时真实存在的,可以在同一时刻运行多个进程。
进程控制块:PCB - 进程控制块(Processing Control Block),Linux内核的进程控制块本质上是一个叫做 task_struct的结构体。在这个结构体中记录了进程运行相关的一些信息
进程一共有五种状态分别为:创建态,就绪态,运行态,阻塞态(挂起态),退出态(终止态)其中创建态和退出态维持的时间是非常短的,稍纵即逝。
ps aux 查看进程信息 kill 杀死进程
liuchang@DESKTOP-LIUCHANG:~/codetest$ ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 916 544 ? Sl Dec18 0:00 /init root 24651 0.0 0.0 916 92 ? Ss 10:58 0:00 /init root 24652 0.0 0.0 916 92 ? S 10:58 0:00 /init liuchang 24653 0.0 0.0 4636 828 pts/0 Ss+ 10:58 0:00 sh -c "$VSCODE_WSL_EXT_LOCATION/scripts/wslServer.sh" b7886d7461186a5eac768481578c1d7ca80e2d21 stable code-server .vscode-server --host=127.0.0.1 --port=0 --connecti liuchang 24654 0.0 0.0 4636 876 pts/0 S+ 10:58 0:00 sh /mnt/c/Users/Liuchang/.vscode/extensions/ms-vscode-remote.remote-wsl-0.77.0/scripts/wslServer.sh b7886d7461186a5eac768481578c1d7ca80e2d21 stable code-server .vsco liuchang 24659 0.0 0.0 4636 864 pts/0 S+ 10:58 0:00 sh /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/bin/code-server --host=127.0.0.1 --port=0 --connection-token=1794849578-1708241527-4087 liuchang 24663 0.0 0.0 951772 77072 pts/0 Sl+ 10:58 0:03 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/out/server liuchang 24674 0.0 0.0 658924 52708 pts/0 Rl+ 10:58 0:04 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/out/bootst liuchang 24734 0.9 0.1 11538640 166668 pts/0 Sl+ 10:58 1:31 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/out/bootst liuchang 24758 0.0 0.0 717340 44276 pts/0 Sl+ 10:58 0:00 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/out/bootst liuchang 24771 0.0 0.0 23076 5092 pts/4 Ss 10:58 0:00 /bin/bash --init-file /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/out/vs/workbench/contrib/terminal/browser/media/shellIntegration-bas liuchang 24790 0.0 0.0 89636 23652 pts/0 Sl+ 10:58 0:03 /home/liuchang/.vscode-server/extensions/ms-vscode.cpptools-1.19.1-linux-x64/bin/cpptools liuchang 24911 0.0 0.0 4269724 14372 pts/0 Sl+ 10:58 0:00 /home/liuchang/.vscode-server/extensions/ms-vscode.cpptools-1.19.1-linux-x64/bin/cpptools-srv 24790 {4FDAC924-C29C-4EC1-A9E5-E1E1D23C8266} root 24959 0.0 0.0 916 92 ? Ss 12:17 0:00 /init root 24960 0.0 0.0 916 92 ? S 12:17 0:00 /init liuchang 24961 0.0 0.0 596084 37636 pts/2 Ssl+ 12:17 0:00 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node -e const net = require('net'); process.stdin.pause(); const client = net.createConne root 24968 0.0 0.0 916 92 ? Ss 12:17 0:00 /init root 24969 0.0 0.0 916 92 ? S 12:17 0:00 /init liuchang 24970 0.0 0.0 594684 37320 pts/1 Ssl+ 12:17 0:00 /home/liuchang/.vscode-server/bin/b7886d7461186a5eac768481578c1d7ca80e2d21/node -e const net = require('net'); process.stdin.pause(); const client = net.createConne liuchang 31668 0.0 0.0 37848 3392 pts/4 R+ 13:32 0:00 ps aux
getpid:获取当前进程的ID
getppid:获取父进程的ID
fork:创建一个新的进程
fork函数
int number = 10; int main(){ cout<<"创建子进程之前numeber = "<<number<<endl; pid_t pid = fork(); cout<<"当前进程fork()返回值 "<<pid<<endl; //如果是父进程 if(pid > 0) { printf("我是父进程, pid = %d, number = %d\n", getpid(), ++number); //11 printf("父进程的父进程(终端进程), pid = %d\n", getppid()); sleep(1); } else if(pid == 0) { // 子进程 number += 100; printf("我是子进程, pid = %d, number = %d\n", getpid(), number); //110 printf("子进程的父进程, pid = %d\n", getppid()); } return 0; }
父子进程虚拟地址空间:
- 各自拥有独立的虚拟地址空间
- 父子进程共享代码段(只读)
- 采用写时拷贝计算创建子进程虚拟地址空间:写时拷贝指只创建虚拟地址空间,不为子进程分配实际的内存,父进程和子进程之间共享相同的物理内存页面。当子进程或父进程对虚拟地址空间对应的内存进行更改时才会分配实际内存。
- 节省内存开销
- 提高创建进程效率
结束进程:
exit()或者_exit()函数,函数的参数相当于退出码
孤儿进程:父进程由于某种原因先退出了,子进程还在运行,这时候这个子进程就可以被称之为孤儿进程。当检测到某一个进程变成了孤儿进程,这时候系统中就会有一个固定的进程领养这个孤儿进程。
系统为什么要领养这个孤儿进程呢?
在子进程退出的时候, 进程中的用户区可以自己释放, 但是进程内核区的pcb资源自己无法释放,必须要由父进程来释放子进程的pcb资源,孤儿进程被领养之后,操作系统释放资源,这样可以避免系统资源的浪费。
僵尸进程
:已经终止执行的进程,父进程没有它的回收资源,用户区资源已经被释放了,只是还占用着一些内核资源(PCB)。
- 进程资源表浪费
- 父进程资源泄露
- 进程通信异常
- 系统性能下降。
如何避免僵尸进程?使用wait()或waitpid()系统调用来等待子进程的退出,并释放相关资源,来避免僵尸进程产生。
- wait()为阻塞方式。如果没有子进程退出, 函数会一直阻塞等待, 当检测到子进程退出了, 该函数阻塞解除回收子进程资源。这个函数被调用一次, 只能回收一个子进程的资源,如果有多个子进程需要资源回收, 函数需要被调用多次。
- waitpid()是非阻塞方式。通过该函数可以控制回收子进程资源的方式是阻塞还是非阻塞,另外还可以通过该函数进行精准打击,可以精确指定回收某个或者某一类或者是全部子进程资源。
守护进程是一种在系统后台运行的特殊进程,独立的提供服务或执行任务,无需与用户交互,系统启动时自动启动,具有稳定性和长时间运行的能力。
守护进程PPID = 1,没有控制终端。
创建守护进程的过程:
- 创建子进程, 让父进程退出,子进程没有任何职务, 目的是让子进程最终变成一个会话, 最终就会得到守护进程。
- 通过子进程创建新的会话,调用函数 setsid(),脱离控制终端。
- 子进程调用fork成功,子进程调用exit(0)终止。由孙进程来充当守护进程,防止子进程成为会话首进程出现异常。
- 改变当前进程的工作目录 (可选项, 不是必须要做的)。
- 重新设置文件的掩码 (可选项, 不是必须要做的)。
- 关闭/重定向文件描述符 (不做也可以)
- 孙进程忽略SIGCHLD信号
- 根据实际需求在守护进程中执行某些特定的操作
参考列表
https://subingwen.cn/linux/file-descriptor/
https://space.bilibili.com/397638507/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。