根据维基百科 :
页面错误是当程序访问虚拟地址空间中映射的页面但不加载到物理内存中时硬件引发的软件陷阱。 (重点是我的)
好的,这是有道理的。
但是,如果是这样的话,为什么每当Process Hacker中的进程信息被刷新时,我就看到大约15页错误?
或换句话说,为什么有任何记忆被分页? (我不知道它是用户还是内核内存。)我没有页面文件,内存使用量是4 GB中的1.2 GB,这是干净的重新启动之后。 没有任何资源短缺, 为什么会有东西被分页?
(我是Process Hacker的作者。)
首先:
页面错误是当程序访问虚拟地址空间中映射的页面但不加载到物理内存中时硬件引发的软件陷阱。
这是不完全正确的,稍后在同一篇文章中解释( 小页面错误 )。 有软页面错误,所有的内核需要做的是添加一个页面到进程的工作集。 下面是Windows内幕书(我已经排除了导致访问冲突的内容)的表格:
页面错误可能由于各种原因而发生,如上所述。 其中只有一个与磁盘读取有关。 如果您尝试从堆中分配一个块并且堆管理器分配新的页面,然后访问这些页面,您将得到一个零页面请求错误。 如果尝试通过写入kernel32的页面来挂钩kernel32中的某个函数,将会得到一个copy-on-write错误,因为这些页面正在悄悄地被复制,所以你的改变不会影响其他进程。
现在要更具体地回答您的问题:Process Hacker在更新其服务信息时似乎只有页面错误 – 也就是说,在调用EnumServicesStatusEx时 ,将哪些RPC调用到SCM(services.exe)。 我的猜测是,在这个过程中,大量的内存被分配,导致需求零页错误(服务信息需要几个页面来存储,IIRC)。
一个缓慢但稳定的页面错误源是操作系统探测不常访问的页面。 在这种情况下,操作系统将某些页面标记为不存在,但将其保留在内存中。 如果应用程序访问该页面,则会发生#PF陷阱,操作系统只是简单地将该页面标记为再次出现。 如果一个“长时间”通过,并且一个页面从不绊倒一个故障,那么操作系统知道这个页面是一个很好的候选交换,如果需要的话。 这个机制即使在没有资源压力的情况下也能主动运行。
“虚拟地址空间中映射的页面,但没有加载到物理内存”并不意味着它以前在物理内存中。 假设你映射一个文件? 它仍然在磁盘上,不在内存中。
假设你映射一个日志文件并继续追加它。 每当您超出已提交内存的末尾时,就会发生页面错误,操作系统会为您提供新的空白页面并调整文件长度。
这也可能是由程序捕获和处理的访问违规。
也可能是程序使用的内存段多于TLB(这是页表的缓存)。 当页面连续时,它们都可以由一个单页表项来处理。 但是,如果内存在物理地址空间中被分割,则需要许多页表项,并且它们可能不适合于TLB。 当发生TLB未命中时,将调用操作系统页面错误处理程序,并在进程的页表中查找映射。
在某些方面,这是Dean的回答中的一个变体:页面已经在物理RAM中,操作系统确实需要将这些映射加载到TLB中,但不是因为IPC。
Brian指出,x86(以及所有的Win32系统)在没有页面错误的情况下处理这个问题。
页面错误的另一个原因是触发用于堆栈增长和写入时复制的防护页面,但通常这些页面不会无界限地发生。 我不能100%确定这些是否会显示为访问违规,因为它们在进入MMU陷阱时会被标记为访问冲突,但可能由操作系统页面错误处理程序处理,并且不会转换为用户模式(SEH)访问冲突。
任何时候读取mmap的部分,都会产生页面错误,包括每当你加载一个DLL。 因此,加载一个DLL实际上并不是将所有的DLL读入内存,它只会导致它在代码执行时出错。
当进程之间共享内存时,您将看到软页面错误 。 基本上,如果在两个进程之间共享一个内存映射文件,当第二个进程加载内存映射文件时,会生成软页面错误 – 内存已经在物理RAM中,但是操作系统需要修复内存管理器的表,以便您的进程中的虚拟内存地址指向正确的物理页面。
特别是对于像Process Hacker这样可能将代码注入每个正在运行的进程(为了收集信息)的应用程序而言,可能会使用共享内存来使用IPC。
操作系统使用分页将物品分组放在物理内存中,并在物理内存和共享内存之间移动。 大部分时间,数据项目在一个页面中,都是相互关联的。 当页面中的数据项长时间不使用时,操作系统将其移动到虚拟内存中以释放物理内存中的一些空间。 然后当虚拟内存中需要页面时,操作系统将其从虚拟内存(硬盘)移动到物理内存。 这是页面错误!
记住,不同的操作系统在分页算法上是不同的。
页面错误的基本知识
资源分配是保持主存储器可用并防止需要尽可能地去中学之间的微妙平衡。 如果一个进程试图分配内存,不能通常是一个例外,有时是一个致命的异常。
从本质上说,你不能把所有东西放在RAM中,因为没有可用的资源,因为当一个程序启动或者要求更多时它会崩溃。