关于进程的概念,一直没有清晰地概念,一直仅仅了解进程是一个应用程序,但是一个应用程序也可以拥有多个进程;
进程:就是出于执行期的程序,但进程又并不仅仅局限于一段可执行程序代码,通常进程还要包含其他资源,像打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程,当然还包括用来存放全局变量的数据段等,实际上,进程就是正在执行程序代码的实时结果,内核需要有效而又透明的管理所有细节。
在现代操作系统中,进程提供两种虚拟机制,虚拟处理器和虚拟空间;意思就是虽然实际上可能许多进程正在分享一个处理器,但是虚拟处理器给进程一种独享这个处理器的感觉,虚拟空间也是一样,让进程在分配和管理内存的时候觉得自己拥有整个系统上的所有内存资源。
个人觉得虚拟处理器就有点像java虚拟机的概念,代码先交给Java虚拟机进行处理,然后交给电脑的cpu进行处理,就相当于虚拟了一个处理器出来;而虚拟空间我以前经常听说过这个名词,一直没搞懂。
谈到虚拟空间就说起来linux的内存管理了,我们知道我们个人计算机的内存相对于硬盘来说是很小的,正常的4G,而cpu的作用就是用来处理数据的,但这个数据不能直接从硬盘过来,只能经过内存来在提交给cpu,换句话来说,我们计算机上运行的所有软件都必须经过内存,那么我们知道现在软件越来越复杂了,特别是那种大型的3d游戏,需要的内存何止4G,所以4G内存是很小了,可能一个稍微大型的程序占用就不止4G了,更别说我们的电脑还需要运行其他的程序(进程)了,但是我们的电脑就是做到了这些,到底是怎么实现的呢?
从网上拷的一张图,可以很清晰的看出,4G的内存其中的1G被分配给了内核空间,可以粗糙的理解为操作系统,被接下来的所有进程所共享,剩下的3G每个进程都被分配了3G,我当时也是一脸懵逼,这不符合数学逻辑啊,就3G的内存,一个进程就占满了,还每个进程都分3G,是不是做梦呢?
其实,这个所谓的每个进程有4g内存,并不是简单的把所有进程的内存相加起来,他强调的是共享内存,在我看来,虚拟内存仅仅是一个概念,他并不能存储东西,所有的数据还是要存储在物理内存中,我们都知道,cpu处理的数据都是从物理内存中得到的,我们可以吧物理内存想像成一个一维数组,cpu要从内存中拿数据,就必须要知道数据存在内存中的哪里,这就是所谓的寻址,如果没有虚拟内存,cpu直接在物理内存上寻址,物理内存上存储的数据繁多而且复杂,如果物理寻址,那么cpu大部分的时间都需要去计算数据在哪里,这就有点大材小用了,浪费cpu性能,所以就有了虚拟内存这个概念,虚拟内存上的地址是连续的,简而言之,就是好找,这样cpu在需要数据时,只需要在虚拟内存上找,虚拟内存再通过mmu上的页表(其实上面存储的就是虚拟内存到物理内存上的映射)去找到对应物理内存上的地址,在虚拟内存上的地址就是所谓的逻辑地址,物理内存上的就是物理地址,这样,就大大节省了cpu寻址的时间,提升性能。当然,这只是虚拟内存的一部分功能,虚拟内存的作用还不止这些,引用一个博客的一段话:
虚拟内存的作用:
1. 内存访问保护
2. 按需分页(lazy load技术)
3. 页换入换出(page swap in/out)
4. 写时复制(copy on write)
1.首先内存访问保护好理解,当我们使用虚拟内存之后,我们看见的就不是真实的物理内存地址了,我们看到的就是虚拟地址也就是逻辑地址,这一步是所谓的内存地址虚拟化,有了这个,我们就可以把通过段界限或页表项去设置程序运行的空间,保证程序只在他的空间内运行,不会越界;
2.按需分页其实也是一个道理,因为有了内存地址虚拟化,我们就可以在程序真正访问到某虚拟内存地址时才会给他分配具体的物理内存,这就是所谓的按需分页;
3.页换入换出就是利用局部性原理,把所要运行的程序不全部加载到内存中,把那些经常访问的部分加载到内存中,不经常使用的放在磁盘中,等到需要了,再通过页换入换出加载到内存。
4.写时复制就是两个虚拟页的数据相同时,可以只分配一个物理页框,这样如果对两个虚拟也的访问时只读,那么在内存中仅仅有一份,节省了物理空间,只会在cpu对其中的一个虚拟页进行写操作时,才会另外在物理内存中拷贝一份,这个技术被应用到进程fork()其子进程时,子进程不会拷贝父进程的内容,只会在使用到父进程中的数据才会拷贝。这就是所谓的写时拷贝。
说了这么多,有些跑题了,这篇博客题是进程管理,而不是内存管理,那么接下来继续。
我们讲进程管理,那么进程要怎么描述呢?linux中使用了一种叫进程描述符(task_struct)的数据结构,它包含了一个具体进程
的所有信息,具体可以包括它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其他更多的信息。
那么计算机不止一个进程,那么也就不会只有一个进程描述符,那么一堆进程描述符怎么去存放呢?linux内核把进程的列表存放在叫做任务队列的双向循环链表中,为什么要使用这个数据结构,无非就是为了好找,好访问。