发件人:Steve Summit
日期:2001年10月15日 21:48:01 -0400
主题:Re: C.L.C FAQ中的一个问题
Message-Id: <2001Oct15.2148.scs.001@aeroroot.scs.ndip.eskimo.net>
[这个问题的意义] 主要是试图平息一场老生常谈、反复出现的“火焰战争”。
故事的第一部分是,曾经有人声称发现许多程序申请的内存(malloc)远远超过它们实际使用的内存。但内核必须为这些内存分配虚拟内存(物理内存和/或交换空间中的后备存储),因为程序可能会用到它;内核无法得知。这可能(这仍然是“据称”;我个人没有见过这些报告)导致大量“浪费”的交换空间,如果交换空间过早耗尽,会产生不良影响。
故事的第二部分是,一些版本的Unix(我相信包括AIX和IRIX)采用了“延迟”分配策略。当程序调用malloc时(或者更准确地说,当malloc调用brk来扩展程序的数据空间时),内核实际上并不会立即分配任何内存,无论是物理内存还是交换空间。如果程序试图使用该内存,就会发生页面错误,在处理页面错误时,内核会发现该页面还没有后备存储,并即时分配它。
但故事的第三部分是,这里有一个潜在的问题:如果这时没有可用的交换空间怎么办?内核现在陷入了困境:它已经向调用程序承诺可以使用该内存(这个承诺是在malloc/brk调用成功时做出的),但现在内核可能不得不收回这个承诺。
故事的第四部分是,在支持这种“延迟”分配策略的内核下,内核可以发送一个或两个新的信号。它实际上可以对一个进程说:“噢,糟糕,我没有交换空间了,想办法处理吧。”可能有两个这样的信号,一个是非致命的,要求程序释放一些内存来腾出一些交换空间,以便内核能够满足页面错误;第二个是致命的,在回收尝试失败后发送。我不清楚这些信号是发送给刚刚遇到无法满足的页面错误的进程,还是发送给内核希望从中抢占一些内存或交换空间的其他进程。
故事的第五部分是,有些人(包括我)认为这是一个糟糕的策略,无论它多么善意,或者无论内存过度分配但未使用的交换空间问题有多么真实。当malloc成功时,意味着我确实获得了内存,如果我后来因为内核“超额预订航班”(quote)而收到信号被杀死,我会非常生气。当然,我可以捕获相关的信号来保护自己(即,至少在第二个致命信号杀死我之前,将任何关键的内存数据保存到磁盘),但这对我来说是一种意外的、非默认的操作,而且不幸的是,在这个系统上,如果我不加倍小心地保护自己(或者甚至不知道我必须这样做),默认情况下似乎是我会输。
不喜欢延迟分配策略的人希望能够指向C语言标准说:“看,如果malloc成功了,我就应该能够使用那段内存;一个符合标准的实现不允许违背这个承诺。”但是故事的第六部分是,延迟分配策略的辩护者也可以指向标准说:“看,里面没有任何东西禁止这样做。”而且他们说得对。