虚拟内存是将系统硬盘空间和系统实际内存联合在一起供进程使用,给进程提供了一个比内存大得多的虚拟空间。在程序运行时,只要把虚拟地址空间的一小部分映射到内存,其余都存储在硬盘上(也就是说程序虚拟空间就等于实际物理内存加部分硬盘空间)。当被访问的虚拟地址不在内存时,则说明该地址未被映射到内存,而是被存贮在硬盘中,因此需要的虚拟存储地址随即被调入到内存;同时当系统内存紧张时,也可以把当前不用的虚拟存储空间换出到硬盘,来腾出物理内存空间。系统如此周而复始地运转——换入、换出,而用户几乎无法查觉,这都是拜虚拟内存机制所赐。
Linux的swap分区就是硬盘专门为虚拟存储空间预留的空间。经验大小应该是内存的两倍左右。有兴趣的话可以使用 swapon -s 查看交换分区大小。
第一层理解
1. 每个进程都有自己独立的4G内存空间,各个进程的内存空间具有类似的结构
2. 一个新进程建立的时候,将会建立起自己的内存空间,此进程的数据,代码等从磁盘拷贝到自己的进程空间,哪些数据在哪里,都由进程控制表中的task_struct记录,task_struct中记录中一条链表,记录中内存空间的分配情况,哪些地址有数据,哪些地址无数据,哪些可读,哪些可写,都可以通过这个链表记录
问题:
计算机明明没有那么多内存(n个进程的话就需要n*4G)内存
建立一个进程,就要把磁盘上的程序文件拷贝到进程对应的内存中去,对于一个程序对应的多个进程这种情况,浪费内存!
第二层理解
1. 每个进程的4G内存空间只是虚拟内存空间,每次访问内存空间的某个地址,都需要把地址翻译为实际物理内存地址
2. 所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物理内存上。
3. 进程要知道哪些内存地址上的数据在物理内存上,哪些不在,还有在物理内存上的哪里,需要用页表来记录
4. 页表的每一个表项分两部分,第一部分记录此页是否在物理内存上,第二部分记录物理内存页的地址(如果在的话)
5. 当进程访问某个虚拟地址,去看页表,如果发现对应的数据不在物理内存中,则缺页异常
6. 缺页异常的处理过程,就是把进程需要的数据从磁盘上拷贝到物理内存中,如果内存已经满了,没有空地方了,那就找一个页覆盖,当然如果被覆盖的页曾经被修改过,需要将此页写回磁盘
总结:
1)进程在创建时会分配4G的虚拟内存空间,并非实际的内存,里面的内容指向物理内存+磁盘。
2)内存用分页来管理这个信息,标项一部分记载所需资源是否在物理内存上,一部分记载在物理内存页的哪里。
3)所以fork创建进程时,复制父进程的内存资源,其实只是复制资源指针到虚拟内存页中。
4)进程访问某个虚拟地址,去看表,如果数据能在物理内存找到则调用,找不到就执行缺页处理,从磁盘复制到内存,如果内存紧张就把暂时不用的资源调到swap。
当你读写文件的时候,Linux内核为了提高读写性能与速度,会将文件在内存中进行缓存,这部分内存就是Cache Memory(缓存内存)。即使你的程序运行结束后,Cache Memory也不会自动释放。这就会导致你在Linux系统中程序频繁读写文件后,你会发现可用物理内存会很少。
其实这缓存内存(Cache Memory)在你需要使用内存的时候会自动释放,所以你不必担心没有内存可用。如果你希望手动去释放Cache Memory也是有办法的。
如何释放Cache Memory(缓存内存):
用下面的命令可以释放Cache Memory:
To free pagecache:
echo 1 > /proc/sys/vm/drop_caches
To free dentries and inodes:
echo 2 > /proc/sys/vm/drop_caches
To free pagecache, dentries and inodes:
echo 3 > /proc/sys/vm/drop_caches