![页面错误、奇怪的内存行为和页面文件 - 特别是但不是专门在 R 中](https://linux22.com/image/1532907/%E9%A1%B5%E9%9D%A2%E9%94%99%E8%AF%AF%E3%80%81%E5%A5%87%E6%80%AA%E7%9A%84%E5%86%85%E5%AD%98%E8%A1%8C%E4%B8%BA%E5%92%8C%E9%A1%B5%E9%9D%A2%E6%96%87%E4%BB%B6%20-%20%E7%89%B9%E5%88%AB%E6%98%AF%E4%BD%86%E4%B8%8D%E6%98%AF%E4%B8%93%E9%97%A8%E5%9C%A8%20R%20%E4%B8%AD.png)
我应该从一开始就说,我意识到我可能需要更多的 RAM,因为我目前在安装了 4GB RAM 的 Windows 10 上运行 RStudio。这篇文章不一定只与 R 有关,而是与内存处理有关。重新启动计算机和 RStudio 后,根据任务管理器,我通常有 2 到 2.5GB 的“可用”RAM。
我的一些代码运行完美(特别是当我使用 data.table 时),即使它需要进行大量计算;生成组合和排列,以及相对复杂的连接。其他工作有 5 次中有 4 次会失败,错误有些模糊,乍一看似乎是随机的;例如 SET_STRING_ELT() 的值必须是“CHARSXP”。
这不是代码或文件错误,也不是执行任何特别复杂的代码(只是打开文件、重新排列某些字段、改变大小写并重新写出)。如果我多次或逐段重新运行完全相同的代码,它最终会起作用,唯一的决定因素显然是最初的运气。
我从中发现了一些模式。例如,它似乎与时间有关。如果我手动拖动并逐个运行各个部分,它就会起作用。使用基础 R“read.csv”循环导入 10MB 文件将与较大文件的 rbindlist 函数一起工作;直到任务管理器中的“可用”RAM 限制。但如果我尝试循环遍历 100MB 文件的基础 R“read.csv”类型导入,错误就会开始显示,即使我明确从环境中删除该对象,然后立即调用 gc(),根据任务管理器,可用 RAM 显然是原来的 10 倍以上,重新启动后,没有其他任何运行。我想到唯一的解决方案是在每个 gc() 和“read.csv”循环后添加 10 秒或更长时间的系统睡眠;这很荒谬,因为这些文件需要几百毫秒才能从 SSD(Kingston V300,~500MB/s)读取,但却神秘地起作用(SET_STRING_ELT() 的值必须是“CHARSXP”错误消失)。
无论如何,我都计划对计算机进行一些升级(购买更多 RAM),但我认为我会通过性能监视器运行一些工作来做一些调查,以查看实际上是什么阻碍了计算机的运行(购买更高速度的 RAM 是否值得等);因为 i3 4130t 处理器(英特尔最便宜的处理器之一)的运行效率很少超过 50%,而且所有四个逻辑处理器显然都很忙(使用 Microsoft MRAN R Open)。
查看不同的代码片段,该代码循环遍历一个 10 MB 左右的 UID 表和第二个表的子集,并在性能监视器结果中,我注意到只要单击运行,页面错误就会持续增加;在系统缓存不断下降的情况下,它会上升到每分钟 5000 次左右。有趣的是,这似乎也与循环逐渐减慢相对应。需要几分钟才能覆盖 5% 的条目。但六个小时后,当我回来时,它已经完成了一半,进展缓慢,任何轻微的干扰都会导致 R 完全挂起。我还经常让 R 重置自身或整个操作系统;在运行一小时或几个小时后出现蓝屏时,Windows 有帮助地通知我,它通常是遇到了页面错误。
在 plotly 论坛上可能有类似的相关内容:
“它似乎在不断地读取/写入页面文件。大约 5 分钟后,CPU 使用率为 20%,页面错误数约为 15,000,000。10 分钟后,CPU 使用率为 30%,页面错误数为 65,000,000。“
我读过一篇有趣且获得高度评价的帖子,现在我找不到它了(但认为它发布在这里),关于页面文件,用户指出 Windows 中实际上从来没有任何“可用”的 RAM;它会不断被预先填充,内容会被分页,然后如果其他内容需要空间,则会被转储出来。
对于是否启用页面文件似乎存在一些极其复杂的意见。
我尝试过启用和禁用它,发现出现的页面错误模式相同。
我似乎在 plotly 论坛上观察到了类似 modidum 的情况。尽管显然有足够的“可用”RAM 来执行这些任务,但 R 似乎试图将大量内容分页归档。
我很好奇这是否可能与较新版本的 Windows 中的内存优先级有关。我知道我可以在任务管理器中增加进程的优先级,但这是否真的会增加它的内存分配优先级,而不是仅仅增加处理器线程优先级?有没有办法永久设置这样的优先级而不使用专有软件?我意识到 Windows 正试图通过预先将内容缓存在 RAM 中来提供帮助,但这似乎对 R 没有任何帮助。有没有办法有选择地强制或更改缓存配置文件?对于内存密集型工作,我更希望没有缓存我实际上没有使用的内容。
对于那些对 SSD 感到好奇的人来说,尽管对页面文件进行了大量的读/写操作,并且有目的地从 R 内部大量读取和写入驱动器(一次数十万个文件,达到容量饱和,然后清除并一遍又一遍地重新达到容量饱和),SSD 本身似乎保持良好;根据金士顿的诊断工具,即使使用多年,它也基本上没有问题。
谢谢您的点击。
答案1
查看一段不同的代码,该代码循环遍历一个 10 MB 左右的 UID 表和第二个表的子集,并在性能监视器结果中,我注意到只要我单击运行,页面错误就会持续增加;在系统缓存不断下降的情况下,页面错误会上升到每分钟 5000 次左右。有趣的是,这似乎也与循环逐渐减慢相对应。
我不是开发人员,因此抱歉无法帮助您解答问题的第一部分,但作为工程师,我可以阐明一下硬件/操作系统的关系。
请理解,如果不深入研究操作系统和平台硬件的根本区别(和相似之处),就没有简单的方法可以解释这一点。但以下是:
另外,它可以帮助您了解,在最基本的层面上,整个平台是一个长长的缓存级别阶梯,要么是 CPU 的物理缓存(L1、L2、L3、L4、RAM、HDD 等),要么是进程和操作系统内存管理器的虚拟缓存级别。(进程私有工作集、工作集、待机等)。
页面错误有两种类型:软页面错误和硬页面错误。柔软的页面错误发生在过程请求的页面不在其工作集内,也就是可用的地址范围过程。该页面通常位于 RAM 中,作为任务管理器 (缓存文件) 中“待机”列表的一部分。
说明支持这是一种误导,因为事实上 CPU 映射的所有页面都是系统工作集的一部分。即使是缓存文件。
CPU 知道请求页面在主存储 (RAM) 或辅助存储 (HDD) 中的位置 - RAM 或 HDD(又称缓存级别 - 你明白了吗?)。它不关心其他任何事情。
CPU 不会移动页面,它只会移动指针。
总结一下:软故障是指进程地址空间的调入调出 - 例如从工作集调到待机再调回。不过这并不是什么大问题。
A难的当请求的页面不在 RAM 中而是在硬盘页面文件中时,就会发生页面错误。当页面文件关闭时,不会发生硬页面错误(显然)。
如果在有可用内存时发生软故障,可以通过增加工作集大小(注册表和 GPO 编辑器)、添加 RAM 或两者来减少。
我读过一篇有趣且获得高度评价的帖子,现在我找不到它了(但认为它发布在这里),关于页面文件,用户指出 Windows 中实际上从来没有任何“可用”的 RAM;它会不断被预先填充,内容会被分页,然后如果其他内容需要空间,则会被转储出来。
不对。
应该至少有一些释放 RAM 以获得最佳性能,以便页面可以直接从驱动器中读取。否则,必须先丢弃备用页面并更新页表。这需要时间。
如果没有任何可用空间,则机器需要更多的 RAM。
对于是否启用页面文件似乎存在一些极其复杂的意见。
我尝试过启用和禁用它,发现出现的页面错误模式相同。
这一页文件是针对具有 32 位地址引脚的 Intel IA-32e/Intel-64 处理器的要求,用于运行带有 PAE 的 Windows x86 或 Windows 64 的 RAM。
页面文件是这些 CPU 能够到达 4GB 以上地址的唯一方式,而操作系统完全有能力做到这一点。
与流行的说法相反,操作系统中的 PAE 代表页地址扩展不是物理地址扩展。页面地址扩展允许操作系统访问高于 4GB 的地址,前提是 CPU 具有 36 位内部寄存器。
如果在具有 32 位寄存器的 CPU 上启用了页面地址扩展,那么一切都会变得很糟糕。32/32 CPU(32 个外部引脚/32 个内部寄存器)可以达到高达 4GB 的地址。
编辑:我添加了一些随机但相关的观点来帮助澄清整体情况......希望我没有做过头。
E**注意:之前我错误地将 IA-64 命名为 x86-64,它应该读作Intel-64。
IA-64是 x64。
** 32/36 (IA32e/Intel 64) AKA x86-64 可以寻址高于 4GB 的 2x 4GB 段。一个 4GB 段是 RAM,另一个段是页面文件。主存储和辅助存储。RAM ---> CPU:外部地址引脚,CPU------> HDD:内部数据寄存器。
36 位页面地址扩展将 IA32e/Intel64 上每个进程的地址空间减少到 3.5GB,其中 512MB 保留给 CPU 页表目录,额外的 4 位用于段目录指针
有没有想过为什么 x87 编译的游戏似乎从未使用超过 3.6GB 的空间?这是因为高指针被英特尔编译器截断了。其余约 512MB 被标记为保留。在 64 位硬件上,VAD 的 500MB 左右的进程被永久标记为可用空间。
Intel IA-32e/Intel-64 也称为 x86-64。x86-64:具有 32 个引脚的 CPU,可通过内部寄存器和硬盘上的页面文件访问 4GB 的 RAM 页。
以上任何一项都不会影响 RAM,顺便说一句,32 针 CPU 无法与密度超过 4GB 的内存模块通信。这是硬件限制。
这就像试图用没有线路的座机给你的朋友打电话一样——只有一部电话。:P
身体的地址扩展是英特尔 CPU 架构术语,指的是 CPU 地址引脚到 RAM。以上内容在英特尔文档中有明确说明。
具有 36 位地址引脚的 CPU 从来不需要页面文件。(AMD64/IA64)
顺便说一句,维基百科、Technet、MSDN 等网站上有关 Windows 内存限制和 PAE 的相关文章大部分都是完全错误或具有误导性的。
微软是这方面最严重的违规者。
我很好奇这是否可能与较新版本的 Windows 中的内存优先级有关。我知道我可以在任务管理器中增加进程的优先级,但这是否真的会增加它的内存分配优先级,而不是仅仅增加处理器线程优先级?有没有办法永久设置这样的优先级而不使用专有软件?我意识到 Windows 正试图通过预先将内容缓存在 RAM 中来提供帮助,但这似乎对 R 没有任何帮助。有没有办法有选择地强制或更改缓存配置文件?对于内存密集型工作,我更希望没有缓存我实际上没有使用的内容。
应该尽可能缓存
这篇文章写得很好,它揭穿了很多错误信息:文件缓存性能和调整。