|

楼主 |
发表于 2006-3-18 10:15:13
|
显示全部楼层
Post by Schwarlz
兄台……把概念理解清楚了再说不迟。
现代操作系统中有两个关键性的概念,其一是作为程序运行实体的进程(也叫任务),其二是进程运行的空间广度,也即地址空间。在x86体系下,地址有三级,其一是逻辑地址,也就是你写汇编时用的那种指定段和偏移的地址;其二是线性地址,不同的进程都可以有一个重合的线性地址集合,即线性地址空间;其三才是真实的物理地址空间。
而你所说的C++的析构函数其实是实现了线性地址空间层次上的资源回收。现代的操作系统普遍支持虚存特性,即把进程运行在其中的地址空间与实际的物理内存空间隔离开来,从而实现多任务“同时”运行。而在主流的32位地址总线系统中,进程可以寻址的线性地址空间是4GB,也就是说,你写程序时可以认为系统有4GB的内存——当然,大多数普通pc都没有这么奢侈的配置——而不必关心真实的物理内存大小,unix/linux的内核自然会把你的4GB的地址空间转换到也许只有512MB的真实物理内存上去运行。从这里就可以看出,当我在程序里malloc了10MB的一块内存时,其实只是将我的地址空间拉长了10MB,也就是告诉内核,“我这个程序现在运行在110MB的空间上,请你分配新的目录和页表以便寻址物理地址”云云,而并不是说真的立刻就在内存中划出10MB空间供使用。事实上,此刻在内存中,你的程序所占的物理地址也许只有5MB不到。
那为什么书上又要说“分配了内存就一定要释放”呢?这是因为你最大的地址空间是有限,对于通常的系统,这个限制是4GB。如果你只malloc不free,那么你的地址空间就被不断地拉长,最后超出4GB的限制,这时内核无法正确做地址转换,就会把向你的进程发送一个SIGSEGV信号,把你的进程强行kill掉,并释放起初为你的进程分配的所有资源,包括任务描述符,段表和页表等等。
而我们所说的操作系统的内存管理是负责逻辑、线性和物理地址转换,以及内存的监视,对缓冲和缓存进行管理的整个sub system,其重要的一个任务便是更加有效地使用内存,包括避免产生控制之外的内存,以及提高程序的响应速度。为此unix/linux的内核都会实现缓冲(cache)与缓存(buffer)两种机制(在2.6系列内核中似乎两部分已经统一了)。缓冲把程序的一部分内容放在内存内,因而你会发现当你关闭一个大的程序后,以后再启动同一程序的速度会变得很快,这其实是因为内核此时并没有从硬盘上读取可执行文件,而是直接执行了内存中的代码。缓存则主要用于硬件i/o操作,当你写一个大文件到硬盘时,你会发现硬盘灯并不是一直亮着,而是一下一下地闪烁,这就是因为数据先被缓存在内存中,到一定数量时才一次性写到硬盘中(也就是sync),这样大大提高了硬盘i/o的效率,也避免了硬盘无谓地损耗。
基于上述的原因,unix/linux内核会尽量使用多的物理内存做缓冲和缓存。但是当内存不够时,内核完全可以在可以忽略的时间内取得足够的内存分配给需要的程序。
上面这段话的关键点是不要搞混编程中的释放内存和内核中的管理内存两个概念。程序中操作的是线性地址空间,而只有内核才会和物理地址空间打交道。而不管你的程序写的多糟糕,只要进程结束,所有的内存立刻都会被内核回收做他用。并不是说如果我的程序malloc后没有free,那么这部分内存就再也没办法再使用了。
谢谢!我看懂你说的意思了。 |
|