标签: virtual-memory

何时做或不做INVLPG,MOV到CR3以最小化TLB刷新

序幕

我是一个操作系统爱好者,我的内核运行在80486+,并且已经支持虚拟内存.

从80386开始,英特尔的x86处理器系列及其各种克隆通过分页支持虚拟内存.众所周知,当设置PG位时CR0,处理器使用虚拟地址转换.然后,CR3寄存器指向顶级页面目录,即用于将虚拟地址映射到物理地址的2-4级页表结构的根.

处理器不会为生成的每个虚拟地址查询这些表,而是将它们缓存在名为Translation Lookaside Buffer或TLB的结构中.但是,当对页表进行更改时,需要刷新TLB.在80386处理器上,此刷新将通过使用顶级页面目录地址或任务切换重新加载(MOV)来完成CR3.这应该无条件地刷新所有TLB条目.据我所知,虚拟内存系统在任何更改后总是重新加载CR3是完全有效的.

这是浪费,因为TLB现在会抛出完全好的条目,因此在80486处理器INVLPG中引入了指令.INVLPG将使与源操作数地址匹配的TLB条目无效.

然而,从Pentium Pro开始,我们还拥有全局页面,这些页面不会被移动到CR3任务切换; 和AMD x86-64 ISA表示某些高级页面表结构可能会被高速缓存而不会失效INVLPG.为了获得每个ISA所需内容和不需要内容的连贯图片,我们真的需要为80年代以来发布的大量ISA下载1000页的数据表来阅读其中的几页,即使这样,文档似乎也是如此对TLB失效特别模糊,如果TLB未正确无效,会发生什么.

为简单起见,可以假设我们正在讨论单处理器系统.此外,可以假设在更改页面结构后不需要任务切换.(因此INVLPG总是被认为至少是重新加载CR3寄存器的好选择).

基本假设是CR3每次更改页面表和页面目录后都需要重新加载,这样的系统是正确的.但是,如果想要避免不必要地冲刷TLB,则需要回答2个问题:

  1. 如果INVLPGISA支持,经过哪种更改可以安全地使用它而不是重新加载CR3?例如"如果一个取消映射一个页面框架(将相应的表条目设置为不存在),则可以始终使用INVLPG"?

  2. 在不触及CR3或执行的情况下,可以对表和目录进行哪些更改INVLPG?例如"如果一个页面根本没有映射(不存在),那么就可Present=1以为它编写一个PTE 而不用刷新TLB"?

即使在阅读了大量的ISA文档以及与INVLPGStack Overflow 相关的所有内容之后,我也不确定我在那里提供的任何一个例子.事实上,一篇值得注意的帖子马上说:"我不知道你何时应该使用它,什么时候不应该使用它." 因此,您可以提供任何特定的,正确的示例,最好是文档,以及您可以给出的IA32或x86-64.

paging x86 x86-64 virtual-memory tlb

23
推荐指数
2
解决办法
4279
查看次数

虚拟内存页面替换算法

我有一个项目,我被要求开发一个应用程序来模拟不同的页面替换算法如何执行(具有不同的工作集大小和稳定期).我的结果:

  • 垂直轴:页面错误
  • 水平轴:工作集大小
  • 深度轴:稳定期

我的结果合理吗?我期望LRU比FIFO更好.在这里,它们大致相同.

对于随机,稳定期和工作集大小似乎根本不影响性能?我预计类似的图表如FIFO和LRU只是性能最差?如果引用字符串是高度稳定的(小分支)并且具有较小的工作集大小,那么具有许多分支和大工作集大小的应用程序应该仍然具有较少的页面错误?

更多信息

我的Python代码 | 项目问题

  • 参考字符串长度(RS):200,000
  • 虚拟内存大小(P):1000
  • 主存储器的大小(F):100
  • 引用的时间页数(m):100
  • 工作组尺寸(e):2 - 100
  • 稳定性(t):0-1

工作集大小(e)和稳定周期(t)会影响参考字符串的生成方式.

|-----------|--------|------------------------------------|
0           p        p+e                                  P-1
Run Code Online (Sandbox Code Playgroud)

因此,假设上面是大小为P的虚拟内存.要生成参考字符串,使用以下算法:

  • 重复直到生成参考字符串
    • m在[p,p + e]中选择数字.m模拟或引用页面被引用的次数
    • 选择随机数,0 <= r <1
    • 如果r <t
      • 生成新的p
      • 别(++ p)%P

更新(回应@ MrGomez的回答)

但是,回想一下您如何播种输入数据:使用random.random,从而为您提供具有可控熵级别的统一数据分布.因此,所有值都可能同样发生,并且因为您在浮点空间中构造了这些值,所以重现非常不可能.

我正在使用random,但它也不是完全随机的,虽然使用工作集大小和数字页引用参数,但是通过某些地方生成引用?

我尝试增加numPageReferenced亲戚,numFrames希望它能更多地引用当前在内存中的页面,从而显示LRU相对于FIFO的性能优势,但这并没有给我一个明确的结果.仅供参考,我尝试使用以下参数的同一个应用程序(页面/框架比率仍然保持不变,我减少了数据的大小以使事情更快).

--numReferences 1000 --numPages 100 --numFrames 10 --numPageReferenced 20
Run Code Online (Sandbox Code Playgroud)

结果是

在此输入图像描述

仍然没有这么大的差异.我是否正确地说,如果我numPageReferenced相对增加numFrames,LRU应该有更好的性能,因为它更多地引用内存中的页面?或许我错误地理解了什么?

对于随机,我正在思考:

  • 假设高稳定性和小工作集.这意味着引用的页面很可能在内存中.那么页面替换算法运行的需求是否较低?

嗯,也许我要考虑更多:)

更新:在较低的稳定性下不太明显的垃圾

在此输入图像描述

在这里,我试图显示垃圾,因为工作集大小超过内存中的帧数(100).然而,通知捶打似乎不太明显,稳定性较低(高t),为什么会这样?解释是,当稳定性变低时,页面错误接近最大值,因此工作集大小是多少并不重要?

operating-system virtual-memory page-replacement

22
推荐指数
1
解决办法
3013
查看次数

在什么情况下大页面可以产生加速?

现代x86 CPU能够支持比传统4K更大的页面大小(即2MB或4MB),并且有操作系统(Linux,Windows)可以访问此功能.

上面的Microsoft链接声明大页面"提高了转换缓冲区的效率,这可以提高频繁访问的内存的性能".这对于预测大页面是否会改善任何特定情况并不是很有帮助.我对具体的,最好是量化的例子感兴趣,其中一些程序逻辑(或整个应用程序)移动使用大页面导致一些性能改进.有人有成功的故事吗?

我知道自己有一个特殊情况:使用大页面可以大大减少分支大型进程所需的时间(可能是因为需要复制的TLB记录数量减少了1000个数量级).我很感兴趣的是,在不那么奇特的场景中,大页面是否也可以带来好处.

performance x86 virtual-memory tlb

20
推荐指数
2
解决办法
2887
查看次数

确定虚拟内存的页表大小

考虑具有38位虚拟字节地址,1KB页面和512 MB物理内存的虚拟内存系统.假设有效,保护,脏和使用位总共占用4位,并且所有虚拟页面都在使用中,则本机上每个进程的页表总大小是多少?(假设磁盘地址未存储在页表中.)

memory paging virtual-memory page-tables

20
推荐指数
2
解决办法
5万
查看次数

Linux零拷贝:使用vmsplice在两个进程之间传输内存页面

目前,我试图了解splice/vmsplice的价值.关于IPC的用例,我在stackoverflow上偶然发现了以下答案:https://stackoverflow.com/a/1350550/1305501

问题:如何使用vmsplice将内存页面从一个进程转移到另一个进程而不复制数据(即零拷贝)?

上面提到的答案声称它是可能的.但是,它不包含任何源代码.如果我理解vmsplice正确的文档,如果内存被正确分配和对齐,以下函数将把内存页面转移到管道(内核缓冲区)而不复制.为了便于演示而省略了错误处理.

// data is aligned to page boundaries,
// and length is a multiple of the page size
void transfer_to_pipe(int pipe_out, char* data, size_t length)
{
    size_t offset = 0;
    while (offset < length) {
        struct iovec iov { data + offset, length - offset };
        offset += vmsplice(pipe_out, &iov, 1, SPLICE_F_GIFT);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如何在不复制的情况下从用户空间访问内存页面?显然,以下方法不起作用:

  • vmsplice:此功能也可用于反向.但根据内核源代码中的注释,数据将被复制.
  • read:我可以想象,如果内存正确对齐,这个函数会产生一些魔力,但我对此表示怀疑.
  • mmap:管道不可能.但是有没有可以使用的某种虚拟文件,即splice虚拟文件的内存页面mmap呢?
  • ......?

根本不可能vmsplice吗?

c linux virtual-memory splice

20
推荐指数
1
解决办法
6288
查看次数

如何可靠地测量Linux中的可用内存?

Linux /proc/meminfo显示了许多内存使用情况统计信息.

MemTotal:      4040732 kB
MemFree:         23160 kB
Buffers:        163340 kB
Cached:        3707080 kB
SwapCached:          0 kB
Active:        1129324 kB
Inactive:      2762912 kB
Run Code Online (Sandbox Code Playgroud)

他们之间有很多重叠.例如,据我所知,可以有活动页面缓存(属于"缓存"和"活动")和非活动页面缓存("非活动"+"缓存").

我想要做的是测量"免费"内存,但其中包括可能被丢弃的已使用页面,而不会对整个系统的性能产生重大影响.

起初,我倾向于使用"免费"+"非活动",但Linux的"免费"实用程序在其"缓冲区调整"显示中使用"自由"+"缓存",所以我很好奇什么是更好的方法.

当内核内存不足时,丢弃页面的优先级是什么?测量可用内存的更合适的度量标准是什么?

linux virtual-memory

19
推荐指数
2
解决办法
1万
查看次数

如何减少cassandra虚拟内存的使用?

cassandra中是否有设置以减少内存使用量?我知道cassandra很好地管理内存,但出于测试目的,我不想只在我的Windows机器上运行cassandra服务时花费6Gb内存.

更新

我已经厌倦了设置disk_access_mode: standart而不是disk_access_mode: auto.没有帮助.另外我注意在cassandra 2.0.9 cassandra.yaml文件中disk_access_mode默认不包含.所以似乎(但我不确定)disk_access_mode是从cassandra中删除的.

java jvm virtual-memory cassandra windows-7

18
推荐指数
2
解决办法
1万
查看次数

Bounds检查64位硬件

我正在hacks.mozilla.org上阅读64位Firefox版本的博客.

作者说:

对于asm.js代码,增加的地址空间还允许我们使用硬件内存保护来安全地从asm.js堆访问中删除边界检查.收益非常显着:asmjs-apps上的8%-17%- * - arewefastyet.com上报告的吞吐量测试.

我试图了解64位硬件如何对C/C++进行自动边界检查(假设编译器支持硬件).我在SO中找不到任何答案.我找到了一篇关于这个主题的技术论文,但我无法理解这是怎么做到的.

有人可以在边界检查中解释64位硬件辅助吗?

c c++ x86-64 sandbox virtual-memory

18
推荐指数
1
解决办法
548
查看次数

建议Prolog处理器使用大页面

是否有任何Prolog实现支持使用大页面(每个内存页2MB/4MB)而不是vanilla 4Kb内存页.

理想情况下,我想向解释器/编译器/运行时声明,对于某些特定应用程序,可以将X大页面用于各种堆/堆栈/暂存器内存.

当然,并非所有应用程序都可以从中受益,但我确信不止一些应用程序会受益.毕竟,兆字节是新的千字节 :)

performance prolog virtual-memory tlb huge-pages

17
推荐指数
1
解决办法
178
查看次数

我的32位应用程序可以做些什么来消耗千兆字节的物理RAM?

几个月前,一位同事提到我,我们的一个内部Delphi应用程序似乎占用了8 GB的RAM.我告诉他了:

那是不可能的

32位应用程序仅具有32位虚拟地址空间.即使存在内存泄漏,它可以消耗的内存最多也是2 GB.之后,分配将失败(因为虚拟地址空间中不会有空白空间).在内存泄漏的情况下,虚拟页面将被换出到页面文件,从而释放物理RAM.

但他指出Windows资源监视器表明系统上可用的RAM不到1 GB.虽然我们的应用程序仅使用220 MB的虚拟内存:关闭它可以释放8 GB的物理RAM.

所以我测试了它

我让应用程序运行了几个星期,今天我终于决定测试它.

首先,我在关闭应用程序之前查看内存使用情况:

  • 工作集(RAM)为241 MB
  • 使用的总虚拟内存:409 MB

在此输入图像描述

我使用资源监视器来检查应用程序使用的内存,以及正在使用的总RAM:

  • 应用程序分配的虚拟内存:252 MB
  • 使用中的物理内存:14 GB

在此输入图像描述

然后关闭应用程序后的内存使用情况:

  • 使用的物理内存:6.6 GB (低7.4 GB)

在此输入图像描述

我还使用Process Explorer来查看前后物理RAM使用情况的细分.唯一的区别是8 GB的RAM 确实是未提交的,现在是免费的:

| Item                          | Before     | After     |
|-------------------------------|------------|-----------|
| Commit Charge (K)             | 15,516,388 | 7,264,420 |
| Physical Memory Available (K) |  1,959,480 | 9,990,012 |
| Zeroed Paging List  (K)       |    539,212 | 8,556,340 |
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

注意:Windows有时会浪费时间将所有内存清零,而不是简单地将其放在备用列表中,并根据需要将其清零(因为需要满足内存请求).

这些都没有解释RAM正在做什么(你坐在那里什么!你包含什么!?)

那段记忆里有什么! …

windows delphi winapi delphi-5 virtual-memory

17
推荐指数
1
解决办法
948
查看次数