jjzjj

windows - 在Windows上混淆物理内存

coder 2024-06-12 原文

我有两个线程和一个大型数据集。线程R不断从数据集中读取数据,并向用户展示数据 View 。线程W不断接收远程数据,对其执行一些工作并将其发布到数据集。

线程R需要控制接收数据集一致 View 的粒度。一种解决方案是双重缓冲。 W写一个副本,而R从另一个副本读取,并且当R准备更新时,要么将W的副本原子复制到R(禁止,因为数据集很大且几乎没有变化),要么它们原子地交换副本,并且W带回R的旧版本通过重新应用自上次交换以来的增量更改来复制最新数据(讨厌跟踪这些变化,并且讨厌所有增量都要处理两次)。

我想做的是以下几点:

  • 两个线程独立地保留虚拟只读内存范围,并且两个范围都映射到同一页物理页
  • 线程W安装了一个异常处理程序,该处理程序将写入捕获为只读页面,捕获一个新的物理块,将其映射为可读写,然后让该写入重新尝试
  • ,当R想要原子更新时(R的 View 中已替换W的任何物理页面被释放(或返回到池中),然后这些虚拟内存地址被W的新物理页面支持,然后W将其整个范围标记为只读再次)。

  • 这样可以避免多余的内存副本,跟踪和重新应用增量等需求。

    但是,虽然AFAICT确实允许Windows创建共享内存区域(甚至是自动写时复制内存区域),但它似乎过时了,无法以任何可用的方式显式映射物理页面由W向R发布新 View 。

    我有什么想念的吗? -是否有可能实现这样的事情,即仅通过更改页面映射而无需存储副本即可实现的发布步骤?

    最佳答案

    我认为应该可以通过一些技巧来做一些接近您要求的事情。

    首先,我将描述我认为最简单,最有效,但最不灵活的方法,并将其称为方法A 。要使用这种方法,数据必须按块排列,并且每个块必须完全包含在一个页面中:

  • 使用相同的文件映射对象为W创建一个读/写 View ,为R创建一个写时复制 View 。
  • 每当W想要修改数据块时,它首先会对写时复制 View 中的相应块执行伪写入。

    注意:我相信即使写入并未实际更改内容,写入页面也会导致写入时复制,但是为了安全起见,我建议您避免这种假设,您可以通过在每个页面中都包含一个虚拟字节来做到这一点。数据块,即R将忽略的数据块。然后,W可以递增虚拟字节以确保复制相应的页面。
  • 要进行同步,请丢弃现有的写时复制 View 并创建一个新 View 。

  • 我希望不必要的虚拟写入的开销可以忽略不计,但是对齐块以使它们不与页面边界重叠可能会很不方便。

    如果是这样,方法B 与方法A相同,除了有多个伪字节,它们以一定间隔放置,以确保与该块重叠的每一页至少包含一个伪字节。这会增加虚拟写入的开销,但我不希望它过多。

    但是,W在每次需要进行更改时都要显式地进行这些伪写操作可能很尴尬,例如,如果数据实际上不是按块排列的,或者每个块内都有多个伪字节会很不方便。因此,我们应该考虑使用方法C :
  • 为W创建一个只读 View 和一个读写 View ,以及为R创建一个写时复制 View 。让W使用只读 View 读取数据,但使用读写 View 写入数据。
  • 使用VirtualProtect和PAGE_GUARD保护读写 View 中的所有页面。
  • 触发保护页错误时,让异常处理程序对写时复制 View 中的相应页面进行虚拟写入。在我看来,矢量异常处理程序看起来像最干净的选项。

    注意:我的研究表明,尽管它涉及在页面错误处理程序中故意调用页面错误,但并不是很确定。应该支持它,因为没有任何异常处理程序可以确保它不会引用被调出的数据,但是由于我没有找到明确的声明来建议这样做,因此建议进行一些实验。

  • 方法C的效率可能不如A或B,因为它需要处理额外的页面错误异常,并具有往返内核模式和返回的相应额外往返过程。我也不确定跟踪保护页面所涉及的页面表开销。但是,这可能会更方便,因为从处理代码中消除伪写入会减少该代码需要注意缓冲的程度。

    最终的变体避免了通过使用单个 View 来使处理代码完全意识到缓冲的需要,而不管W是正在读取还是正在写入。 方法D 如下:
  • 为W创建一个读/写 View ,为R创建一个写时复制 View 。
  • 使用VirtualProtect将读/写 View 的所有页面上的权限更改为只读。
  • 触发页面错误时,让异常处理程序将有故障的页面上的权限更改为读/写,并在写时复制 View 中对相应页面进行虚拟写操作。

  • 我认为这种方法效率最低,因为我希望显式更改块的权限比使用保护页面要慢得多。这也可能导致页表的更多碎片。但是,如果事实证明它可以充分发挥作用,那几乎肯定是最方便的解决方案。

    一些附加说明:

    我相信所有这些方法都应该起作用,但要注意一个警告,即处理第一个页面错误时触发第二个页面错误会发生什么。我对不同变体的比较效率没有信心。进行一些比较测试可能是明智的。

    文件映射对象可能应该由页面文件支持,并且您可能想尝试使用大页面。这将增加需要复制的数据量,但会减少页表上的负载。同样,比较测试可能是适当的。

    我认为您已经考虑了这一点,但是 future 的读者应该注意,根据数据的性质,根本不宜使用映射。例如:
  • 可以为数据块提供两个修订号,一个修订号表示该块何时生效,另一个指示何时将其删除。这种方法的时间开销很小,R在处理一个块时只需要检查修订号,以便它可以跳过太新的块并删除过时的块。这涉及较少的数据复制:W只需要复制它正在处理的数据块,而不是整个页面,并且添加/删除块根本不需要复制任何数据。
  • 如果需要按特定顺序链接块,则修订号可能不够,但是您可以为R和W设置单独的链。同步将要求您重新链接块,但是与修改相比,它仍然可能更快。页表。
  • 关于windows - 在Windows上混淆物理内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33152126/

    有关windows - 在Windows上混淆物理内存的更多相关文章

    1. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    2. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    3. ruby-on-rails - Ruby 中的内存模型 - 2

      ruby如何管理内存。例如:如果我们在执行过程中采用C程序,则以下是内存模型。类似于这个ruby如何处理内存。C:__________________|||stack|||------------------||||------------------|||||Heap|||||__________________|||data|__________________|text|__________________Ruby:? 最佳答案 Ruby中没有“内存”这样的东西。Class#allocate分配一个对象并返回该对象。这就是程序

    4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

      这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

    5. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

      之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

    6. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

      深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

    7. 键删除后 ruby​​ 哈希内存泄漏 - 2

      你好,我无法成功如何在散列中删除key后释放内存。当我从哈希中删除键时,内存不会释放,也不会在手动调用GC.start后释放。当从Hash中删除键并且这些对象在某处泄漏时,这是预期的行为还是GC不释放内存?如何在Ruby中删除Hash中的键并在内存中取消分配它?例子:irb(main):001:0>`ps-orss=-p#{Process.pid}`.to_i=>4748irb(main):002:0>a={}=>{}irb(main):003:0>1000000.times{|i|a[i]="test#{i}"}=>1000000irb(main):004:0>`ps-orss=-p

    8. ruby - 如何在 Ruby 中执行 Windows CLI 命令? - 2

      我在目录“C:\DocumentsandSettings\test.exe”中有一个文件,但是当我用单引号编写命令时`C:\DocumentsandSettings\test.exe(我无法在此框中显示),用于在Ruby中执行命令,我无法这样做,我收到的错误是找不到文件或目录。我尝试用“//”和“\”替换“\”,但似乎没有任何效果。我也使用过系统、IO.popen和exec命令,但所有的努力都是徒劳的。exec命令还使程序退出,这是我不想发生的。提前致谢。 最佳答案 反引号环境就像双引号,所以反斜杠用于转义。此外,Ruby会将空格解

    9. ruby-on-rails - HTTParty 的内存问题和下载大文件 - 2

      这会导致Ruby出现内存问题吗?我知道如果大小超过10KB,Open-URI会写入TempFile。但是HTTParty会在写入TempFile之前尝试将整个PDF保存到内存吗?src=Tempfile.new("file.pdf")src.binmodesrc.writeHTTParty.get("large_file.pdf").parsed_response 最佳答案 您可以使用Net::HTTP。参见thedocumentation(特别是标题为“流媒体响应机构”的部分)。这是文档中的示例:uri=URI('http://e

    10. ruby - 关于 Ruby 中 Dir[] 和 File.join() 的混淆 - 2

      我在Ruby中遇到了一个关于Dir[]和File.join()的简单程序,blobs_dir='/path/to/dir'Dir[File.join(blobs_dir,"**","*")].eachdo|file|FileUtils.rm_rf(file)ifFile.symlink?(file)我有两个困惑:首先,File.join(@blobs_dir,"**","*")中的第二个和第三个参数是什么意思?其次,Dir[]在Ruby中有什么用?我只知道它等价于Dir.glob(),但是,我对Dir.glob()确实不是很清楚。 最佳答案

    随机推荐