声明:所有文章只作为学习笔记用,转载非原创
参考 https://www.cnblogs.com/sparkdev/p/8410350.html
https://blog.csdn.net/andylauren/article/details/70094423 进程与内存
理解 https://www.cnblogs.com/mrwuzs/p/11279511.html
寻址
https://www.cnblogs.com/likeyiyy/p/3837272.html
进程调度
https://www.zhihu.com/question/64723752
调度算法:
https://zhuanlan.zhihu.com/p/29668105
打个比方来说明两种调度。我们把操作系统比作公司,把用户程序比作员工。
内核级调度就像流水线。公司规定得非常细致,员工必须严格遵守。任务被公司划分好,工人只能在任务时间内做规定的事,不能私自改变任务的时间长短和先后顺序。
用户级调度就像写字楼。公司规定得比较松散,员工有一定灵活性。老板给员工布置了多个任务,员工可以自己安排任务的时间长短和先后顺序。
再打个比方。我们把操作系统比作交通设施,用户程序比作参与交通的人。
内核级调度很像地铁。每隔一段时间一班,开到你面前的时候(调度到),你才能上车(完成通行任务)。
用户级调度如同自驾。时间你定,路线你定。
怎样观察上下文 vmstat
cs(context switch)是每秒上下文切换的次数。in(interrupt)则是每秒中断的次数。
r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数。
b(Blocked)则是处于不可中断睡眠状态的进程数
1)父进程调用fork() 产生一个新的自进程;
2)子进程调用exec() 指定自己要执行的代码;
3)子进程调用exit() 退出,进入zombie状态;
4)父进程调用wait(),等待子进程的返回,回收其所有资源;
Linux 中每个进程有两个栈,分别用于用户态和内核态。
程序在执行过程中通常有用户态和内核态两种状态,CPU对处于内核态根据上下文环境进一步细分,因此有了下面三种状态:
(1)内核态,运行于进程上下文,内核代表进程运行于内核空间。
(2)内核态,运行于中断上下文,内核代表硬件运行于内核空间。
(3)用户态,运行于用户空间。
上下文context: 上下文简单说来就是一个环境。
进程切换时才需要切换上下文,换句话说,只有在进程调度的时候,才需要切换上下文
而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU 寄存器和程序计数器
CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文
CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加
载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
根据任务的不同,CPU 的上下文切换就可以分为几个不同的场景,也就是进程上下文切换、线程上下文切换以及中断上下文切换。
linux的上下文切换就是进程线程的切换,也就是切换struct task_struct结构体
https://www.cnblogs.com/mrwuzs/p/11279511.html
https://blog.csdn.net/a7980718/article/details/82807986
用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递 很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存 器值、变量等。所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。
https://blog.csdn.net/lijiajia81/article/details/8534704
系统调用(system call):通过软件中断向内核态发出一个明确的请求
应用程序接口(API):只是一个函数定义,说明了如何获得一个给定的服务
系统调用属于内核,而用户态的库函数不属于内核,当用户态的进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。
系统调用处理程序执行下列操作:
1.在内核态栈保持大多数寄存器的内容
2.调用名为系统调用服务例程的相应的C函数来处理系统调用
3.退出系统调用处理程序:用保存在内核栈中的值加载寄存器,CPU从内核态切换回到用户态
fork () 与 vfork()
vfork 共用mm struct
linux 通过 pthread_create (创建线程的API)创建线程 ,调用的就是clone (把所有的资源都clone一份,p2的所有指针都指向p1) linux 就是用这样的方法来实现线程的。所以在linux 中为什么线程也叫轻量级进程(LWP)的原因。
思考: Linux实现进程和线程 ,如果克隆一部分task_struct 那是什么(线程有了进程的心,)
TGID :thread group id。对于同一进程中的所有线程,tgid都是一致的,为该进程的进程ID。
Top 命令看到的就是 TGID
Top -H 看到的是线程ID
进程的托孤: 白发人送黑发人
subreaper : 收割机 (火葬场)
http://www.mamicode.com/info-detail-416154.html
PAGE_OFFSET其实就是物理地址与线性地址之间的位移量。Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的空间分为两部分。将最高的1G字节供内核使用,称为“内核空间”。而将较低的3G字节,供各个进程使用,称为“用户空间)。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间
进程的睡眠:
进程存放哪些数据
https://www.cnblogs.com/senior-engineer/p/10963055.html
BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量和静态变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。
数据段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配。
代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
栈(stack):栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。堆栈又称堆栈(stack)在计算机科学中,是一种特殊的链表形式的数据结构,它的特殊之处在于只能允许在链表的一端(称为栈顶,英文为top)进行添加和删除操作。另外堆栈数据结构的实现也可以通过数组来完成。
严格来说堆是指Heap,程序运行时供程序员来支配的一段内存。而栈Stack,多指函数调用时候参数的相互传递存在的内存区域。由于堆栈数据结构只允许在一端进行操作,因而按照先进后出(LIFO-Last In First Out)的原理工作。堆栈数据结构支持两种基本操作:压栈(push)和弹栈(pop):
1. 压栈(入栈):将对象或者数据压入栈中,更新栈顶指针,使其指向最后入栈的对象或数据。
2. 弹栈(出栈):返回栈顶指向的对象或数据,并从栈中删除该对象或数据,更新栈顶。
VFS : 虚拟文件系统
https://blog.csdn.net/hbcbgcx/article/details/88361530
附加:
Linux 为什么多进程能够读写正在删除的文件
https://blog.csdn.net/weiwangchao_/article/details/94578327
例如,你删除了tcpdump.log,执行lsof | grep tcpdump.log,你应该能看到这样的输出:
tcpdump 2864 tcpdump 4w REG 253,0 0 671457 /root/tcpdump.log (deleted)
然后:
cp /proc/2864/fd/4 /root/tcpdump.log
???什么是逻辑地址、线性地址和物理地址