每一个进程在打开时,都各自有自己的pcb(进程控制块),pcb相当于一个指针,指向文件描述符表,假如一个进程要打开一个文件就会产生一个句柄(文件描述符),该句柄通过pcb指向文件描述符表,通过文件描述符表的内容在磁盘中找到你想打开的文件。pcb在内核中,每一个进程打开时都会有内核层和用户层,其中内核层是不对用户开放的,其中包含命令行参数和环境变量。用户层就是我们常见的堆栈常量区数据区之类的。进程如下图所示。
但是呢在进程中的内存是虚拟内存不是实际的内存,实际的内存是物理内存,所以我们在分配内存的时候,进程中存放的是虚拟内存的地址,操作系统会给该进程分配一块物理内存,然后映射到虚拟内存上,所以你实际的数据都是存放在物理内存上的。当你需要取出数据的时候,指针会指向虚拟内存,然后指向物理内存,在物理内存中取出数据。
每一个进程都有虚拟内存,假如b.out进程在栈中分配一块内存之后,a.out是无法在b.out访问分配的那片内存的,也就是说每一个进程在用户区分配的内存是独立的,如果不独立的话a.out的内容,b.out也可以访问,那么就会造成数据错乱丢失等情况。但是所有的进程是共享内核层的,也就意味着a.out进程的内核层可以看到b.out的pcb的内容。但是不用担心内容会被修改,因为进程只能读写用户空间。不能访问内核空间。
那么操作系统是怎么管理内存的呢?操作系统有一个虚拟内存映射表。里面包含了每个进程的虚拟内存地址映射到物理内存的地址。操作系统按照页(page)对内存进行管理,一般情况下,一页=4096bytes,当我们需要malloc1000个字节的时候,操作系统就给它分配一页,也就是4096个字节。当你在需要分配500个字节的时候,刚才的一页还剩下3096个字节从中在分配出500个字节。但是当你还需要分配3000个字节的时候此时一页已经不够了操作系统就会在给你分配一页。很多人很奇怪这么看来怎么分配不是很重要啊,都是分配那么多的字节,其实不然这涉及到负载均衡的问题,每分配一页都有一定的消耗,在分配内存的时候最好是4096的整数倍。具体的流程,可以看下图,结合起来看理解会容易一点。