前言
这部分让我们来继续了解Linux中进程和计划任务的相关知识吧~
相关技术交流欢迎添加VX: wenjinworkon
目录
进程和内存管理
什么是进程
进程结构
进程相关概念
物理地址空间和虚拟地址空间
用户和内核空间
进程使用内存问题
进程状态
内存淘汰数据机制:LRU算法
IPC 进程间通信
进程优先级
进程分类
进程和内存管理
内核的功能:进程管理、内存管理、文件系统、网络功能、驱动程序、安全功能等
什么是进程
Process:是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
通俗来说:就是程序被加载到内存中,程序一旦被运行就成为了进程。
- 进程ID(Process ID,PID)用来标记各个进程
- UID、GID和SELinux语境决定对文件系统的存取和访问权限
- 通常从执行进程的用户来继承
- 存在声明周期
在Linux中,第一个进程为systemd(init CentOS6之前),所有的进程都由父进程产生。
进程、线程
进程
进程是系统中正在运行的一个程序,程序一旦运行就是进程。
进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体,每个进程都拥有独立的地址空间。一个进程无法访问另一个进程的变量和数据结构,如果想让一个进程访问另一个进程的资源,需要使用进程间通信,比如管道,文件,套接字等。
线程
线程是进程的一个实体,是进程的一条执行路径。
线程是进程的一个特定执行路径。当一个线程修改了进程的资源,它的兄弟线程可以立即看到这种变化。
进程、线程区别
一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间。线程与进程的一个主要区别是,统一进程内的一个主要区别是,同一进程内的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存)。同时,每个线程还拥有自己的寄存器和栈,其他线程可以读写这些栈内存。
查看进程中线程的方法
grep -i threads /proc/PID/status
进程结构
内核把进程存在任务队列(task list)的双向循环链表中
链表中的每一项都是类型为task_struct,称为进程块(Processsing Control Block),PCB中包含一个具体进程的所有信息
进程控制块PCB包含信息
- 进程id、用户id和组id
- 程序计数器
- 进程的状态(有就绪、运行、阻塞)
- 进程切换时需要保存和恢复的CPU寄存器的值
- 描述虚拟地址空间的信息
- 描述控制终端的信息
- 当前工作目录
- 文件描述符表,包含很多指向file结构体的指针
- 进程可以使用的资源上限(ulimit -a 命令可以查看)
- 输入输出状态:配置进程使用I/O设备
进程相关概念
Page Frame:页框,用存储页面数据,存储Page 4K
[root@centos8 ~]#getconf -a |grep -i size
PAGESIZE 4096
PAGE_SIZE 4096
SSIZE_MAX 32767
_POSIX_SSIZE_MAX 32767
_POSIX_THREAD_ATTR_STACKSIZE 200809
FILESIZEBITS 64
POSIX_ALLOC_SIZE_MIN 4096
POSIX_REC_INCR_XFER_SIZE
POSIX_REC_MAX_XFER_SIZE
POSIX_REC_MIN_XFER_SIZE 4096
LEVEL1_ICACHE_SIZE 65536
LEVEL1_ICACHE_LINESIZE 64
LEVEL1_DCACHE_SIZE 32768
LEVEL1_DCACHE_LINESIZE 64
LEVEL2_CACHE_SIZE 524288
LEVEL2_CACHE_LINESIZE 64
LEVEL3_CACHE_SIZE 16777216
LEVEL3_CACHE_LINESIZE 64
LEVEL4_CACHE_SIZE 0
LEVEL4_CACHE_LINESIZE 0
物理地址空间和虚拟地址空间
MMU:Memory Management Unit 负责虚拟地址转换为物理地址
程序在访问一个内存地址指向的内存时,CPU并不是直接把这个地址送到内存总线上,而是被送到MMU,然后把这个内存地址映射到实际的虚拟内存地址上,然后通过总线再去访问内存,程序操作的地址称为虚拟内存地址
MMU:Memory Management Unit 负责虚拟地址转换为物理地址
用户和内核空间
进程使用内存问题
内存泄漏:指程序申请(malloc、new)了一块内存,但是没有用相应的操作(free、delete)将内存释放,导致这个内存一直处于占用状态
内存溢出:指给程序申请了10M的空间,但是在这个空间写入10M以上的字节数据,就是溢出
内存不足:内存耗尽,Linux会选一个进程kill掉,可在messages中看到提示
解决方法:
#调整参数,不允许内存申请过量
echo 2 > /proc/sys/vm/overcommit_memory
echo 80 > /proc/sys/vm/overcommit_ratio
echo 2 > /proc/sys/vm/panic_on_oom
Linux默认是允许memory overcommit的,只要你来申请内存我就给你,寄希望于进程实际上用不到那么多内存,但万一用到那么多了呢?Linux设计了一个OOM killer机制挑选一个进程出来杀死以腾出部分内存,如果还不够就继续。也可通过设置内核参数 vm.panic_on_oom 使得发生OOM时自动重启系统。这都是有风险的机制,重启有可能造成业务中断,杀死进程也有可能导致业务中断。所以Linux 2.6之后允许通过内核参数 vm.overcommit_memory 禁止memory overcommit。
vm.overcommit_memory取值方式:
0 – Heuristic overcommit handling. 这是缺省值,它允许overcommit,但过于明目张胆的
overcommit会被拒绝,比如malloc一次性申请的内存大小就超过了系统总内存。Heuristic的意思是“试探
式的”,内核利用某种算法猜测你的内存申请是否合理,它认为不合理就会拒绝overcommit。
1 – Always overcommit. 允许overcommit,对内存申请来者不拒。内核执行无内存过量使用处理。使
用这个设置会增大内存超载的可能性,但也可以增强大量使用内存任务的性能。
2 – Don’t overcommit. 禁止overcommit。 内存拒绝等于或者大于总可用 swap 大小以及
overcommit_ratio 指定的物理 RAM 比例的内存请求。如果希望减小内存过度使用的风险,这个设置就是
最好的。
进程状态
进程的基本状态
创建状态:进程在创建时需要申请一个空白PCB(process control block进程控制块),向其中填写
控制和管理进程的信息,完成资源分配。如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态就绪状态:进程已准备好,已分配到所需资源,只要分配到CPU就能够立即运行执行状态:进程处于就绪状态被调度后,进程进入执行状态阻塞状态:正在执行的进程由于某些事件(I/O请求,申请缓存区失败)而暂时无法运行,进程受
到阻塞。在满足请求时进入就绪状态等待系统调用终止状态:进程结束,或出现错误,或被系统终止,进入终止状态。无法再执行
相互关系
运行——>就绪:1,主要是进程占用CPU的时间过长,而系统分配给该进程占用CPU的时间是有限的;
2,在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行时,该进程就被迫让出CPU,
该进程便由执行状态转变为就绪状态
就绪——>运行:运行的进程的时间片用完,调度就转到就绪队列中选择合适的进程分配CPU
运行——>阻塞:正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为阻塞状态,如发
生了I/O请求
阻塞——>就绪:进程所等待的事件已经发生,就进入就绪队列以下两种状态是不可能发生的:
阻塞——>运行:即使给阻塞进程分配CPU,也无法执行,操作系统在进行调度时不会从阻塞队列进行挑
选,而是从就绪队列中选取
就绪——>阻塞:就绪态根本就没有执行
Linux中的进程状态
- 运行态:running
- 就绪态:ready
- 睡眠态:可中断:interruptable,不可中断:uninterruptable
- 停止态:stopped,暂停与内存,不会被调度,除非手动启动
- 僵尸态:zomibe,结束进程,父进程结束前,子进程不关闭,可通过杀死父进程关闭僵尸态的子进程
僵尸态
[root@centos8 ~]#bash
[root@centos8 ~]#echo $BASHPID
1809
[root@centos8 ~]#echo $PPID
1436
#将父进程设为停止态
[root@centos8 ~]#kill -19 1436
#杀死子进程,使其进入僵尸态
[root@centos8 ~]#kill -9 1809
[root@centos8 ~]#ps aux #可以看到上面图示的结果,STAT为Z,表示为僵尸态
#方法1:恢复父进程
[root@centos8 ~]#kill -18 1436
#方法2:杀死父进程
[root@centos8 ~]#kill -9 1436
#再次观察,可以僵尸态的进程不存在了
[root@centos8 ~]#ps aux
孤儿进程:
如果在子进程在退出前,父进程先退出,这时子进程将成为孤儿进程,因为它的父进程已经死了。孤儿进程会被PID=1的systemd进程收养,成为systemd的子进程.
注意,孤儿进程还会继续运行,而不会随父进程退出而终止,只不过其父进程发生了改变。
[root@rocky8 ~]#(sleep 100)&
[1] 1388
[root@rocky8 ~]#pstree -s `pidof sleep`
systemd───sshd───sshd───sshd───bash───sleep
#利用()实现当前shell的子进程,&实现后台执行,子进程结束后
[root@rocky8 ~]#(sleep 100 &)
[root@rocky8 ~]#pstree -s `pidof sleep`
systemd───sleep
[root@rocky8 ~]#cat orphan.sh
#!/bin/bash
ping 127.0.0.1 &
echo game over
[root@rocky8 ~]#bash orphan.sh
[root@rocky8 ~]#pstree -s `pidof ping`
systemd───ping
内存淘汰数据机制:LRU算法
喜新厌旧,释放内存
IPC 进程间通信
IPC:Inter Process Communication
同一台主机:
pipe 管道,单向传输
socket 套接字文件,双向通信
Memory-maped file 文件映射,将文件中的一段数据映射到物理内存,多个进程共享这片内存
shm shared memory 共享内存
signal 信号
Lock 对资源上锁,如果资源已被某进程锁住,则其它进程想修改甚至读取这些资源,都将被阻
塞,直到锁被打开
semaphore 信号量,一种计数器
不同主机:IP和端口号
进程优先级
优先级范围 | 描述 |
0-99 | 实时进程 |
100-139 | 非实时进程 |
注意:越靠左,优先级越高
进程分类
- 守护进程:daemon,在系统引导过程中启动的进程,和终端无关
- 前台进程:和终端有关,通过终端启动的进程
可以相互转化
总结:
这样我们就初步了解Linux进程和内存管理相关特性了,欢迎添加VX: wenjinworkon