我知道程序首次启动时,由于代码不在内存中,因此在开始时会出现大量页面错误,因此需要从磁盘加载代码。
程序退出后会发生什么?二进制文件是否留在内存中?该程序的后续调用是否会发现代码已经在内存中,因此没有页面错误(假设没有任何内容运行并且页面填充到磁盘中)?
似乎答案不是在我的Linux机器上运行一些实验。我一遍又一遍地运行一些程序,每次都观察到相同数量的页面错误。这是一个相对安静的机器,所以我怀疑东西是在调用之间被调出来的。那么,为什么呢?为什么可执行文件不能保留在内存中?
答案 0 :(得分:3)
这里有两件事要考虑:
1)可执行文件的内容可能保存在OS缓存(磁盘缓存)中。虽然该数据仍在操作系统缓存中,但该数据的每次读取都将到达缓存,操作系统将遵循请求而无需从磁盘重新读取文件。
2)当进程退出时,操作系统取消映射到文件的每个内存页面,释放任何内存(通常,释放进程分配的每个资源,包括其他资源,如套接字等)。严格来说,物理内存可能已归零,但并不十分必需(仍然,操作系统的安全级别可能需要将不再使用的页面归零 - 可能是Windows NT,2K,XP等,请执行此操作 - 请参阅此Does Windows clear memory pages?)。对同一个可执行文件的另一个调用将创建一个全新的进程,它将在内存中映射相同的文件,但是对这些页面的第一次访问仍然会触发页面错误,因为最终它是一个新进程,一个不同的内存映射。所以是的,页面错误发生了,但与第一个相比,同一个可执行文件的第二个实例便宜得多。
当然,这只是关于可执行文件的只读部分(包含代码和只读数据的段/模块)。
可以考虑另一种情况:分叉。在这种情况下,每个页面都标记为写时复制。当在每个存储器页面上发生第一次写入时,OS内存管理器触发并拦截硬件异常。操作系统确定是否允许写入相关页面(例如:如果它是堆栈,堆或任何可写页面),如果是,则分配内存并复制原始内容 允许进程修改页面 - 以便在其他进程中保留原始数据。是的,还有另一种情况 - 共享内存,其中确切的物理内存映射到两个或多个进程。在这种情况下,写时复制标志当然不会在存储页面上设置。
希望这能澄清内存页面的内容。
答案 1 :(得分:0)
我非常怀疑的是,部件,信息blob不会立即从RAM中删除,除非有实际运行代码的更多RAM的新请求。对于该部分,可能发生的是OS在下一次执行时重新使用来自RAM的OS相关位。我认为这对于OS发起的资源来说是正确的(并且可能不是所有资源都有,但有些资源)。
答案 2 :(得分:0)
实际上,您的大多数问题都是高度依赖于实现的。但对于大多数使用过的操作系统:
程序退出后会发生什么?二进制文件是否留在内存中?
是,但内存块被标记为未使用(因此可以分配给其他进程)。
程序的后续调用是否会发现代码是 已经在内存中,因此没有页面错误(假设没有运行 介于两者之间并将页面输出到磁盘上?
不,这些街区被视为空。部分/全部块可能已被覆盖。
为什么可执行文件不能保留在内存中?
为什么会留下来?进程完成后,将释放所有已分配的资源。
答案 3 :(得分:-1)
其中一个原因是人们通常希望在后续调用中清除所有内容,以防它们在以前的问题中出现问题。
另外,必须移出可写数据。
也就是说,有些系统确实有可以在内存中保存可执行文件和静态数据的机制(可能不是linux)。例如,VMS操作系统允许系统管理器安装可执行文件和共享库,以便它们保留在内存中(允许分页)。可以使用相同的系统创建可创建的可写共享内存,以允许进程间通信和对内存的修改保留在内存中(可能被分页)。