草庐IT

c++ - ReadProcessMemory 比 SharedMemory 上的 memcpy 更快

coder 2024-02-24 原文

我正在尝试通过使用共享内存进行通信来改进我的多进程应用程序。我正在用简单的测试做一些分析,结果出现了一些奇怪的东西。当我尝试复制存储在 SharedMemory 中的数据时,使用 ReadProcessMemory 比使用 Memcopy 更快。

我知道我不应该那样使用 SharedMemory(最好直接在共享内存中读取),但我仍然想知道为什么会这样。通过进一步调查,另一件事出现了:如果我在同一个共享内存区域(实际上是同一个区域)上执行 2 个连续的 memcpy,则第二个拷贝比第一个快两倍。

这是显示问题的示例代码。在这个例子中,只有一个进程,但问题仍然在这里。从共享内存区域执行 memcpy 比在我自己的进程上执行同一区域的 ReadProcessMemory 慢!

#include <tchar.h>
#include <basetsd.h>
#include <iostream>

#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/windows_shared_memory.hpp>
#include <time.h>
namespace bip = boost::interprocess;
#include <boost/asio.hpp>

 bip::windows_shared_memory* AllocateSharedMemory(UINT32 a_UI32_Size)
{
    bip::windows_shared_memory* l_pShm = new bip::windows_shared_memory (bip::create_only, "Global\\testSharedMemory", bip::read_write, a_UI32_Size);
    bip::mapped_region l_region(*l_pShm, bip::read_write);
    std::memset(l_region.get_address(), 1, l_region.get_size());
    return l_pShm;
}

//Copy the shared memory with memcpy
void CopySharedMemory(UINT32 a_UI32_Size)
{
    bip::windows_shared_memory m_shm(bip::open_only, "Global\\testSharedMemory", bip::read_only);
    bip::mapped_region l_region(m_shm, bip::read_only);
    void* l_pData = malloc(a_UI32_Size);
    memcpy(l_pData, l_region.get_address(), a_UI32_Size);
    free(l_pData);
}

//Copy the shared memory with ReadProcessMemory
void ProcessCopySharedMemory(UINT32 a_UI32_Size)
{
    bip::windows_shared_memory m_shm(bip::open_only, "Global\\testSharedMemory", bip::read_only);
    bip::mapped_region l_region(m_shm, bip::read_only);
    void* l_pData = malloc(a_UI32_Size);
    HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE,(DWORD) GetCurrentProcessId());
    size_t l_szt_CurRemote_Readsize;
    ReadProcessMemory(hProcess,
                      (LPCVOID)((void*)l_region.get_address()),
                      l_pData,
                      a_UI32_Size,
                      (SIZE_T*)&l_szt_CurRemote_Readsize);
    free(l_pData);
}

// do 2 memcpy on the same shared memory
void CopySharedMemory2(UINT32 a_UI32_Size)
{
    bip::windows_shared_memory m_shm(bip::open_only, "Global\\testSharedMemory", bip::read_only);
    bip::mapped_region l_region(m_shm, bip::read_only);
    clock_t begin = clock();
    void* l_pData = malloc(a_UI32_Size);
    memcpy(l_pData, l_region.get_address(), a_UI32_Size);
    clock_t end = clock();
    std::cout << "FirstCopy: " << (end - begin) * 1000 / CLOCKS_PER_SEC << " ms" << std::endl; 
    free(l_pData);

    begin = clock();
    l_pData = malloc(a_UI32_Size);
    memcpy(l_pData, l_region.get_address(), a_UI32_Size);
    end = clock();
    std::cout << "SecondCopy: " << (end - begin) * 1000 / CLOCKS_PER_SEC << " ms" << std::endl; 
    free(l_pData);
}

int _tmain(int argc, _TCHAR* argv[])
{
    UINT32 l_UI32_Size = 1048576000;
    bip::windows_shared_memory* l_pShm = AllocateSharedMemory(l_UI32_Size);
    clock_t begin = clock();
    for (int i=0; i<10 ; i++)
        CopySharedMemory(l_UI32_Size);
    clock_t end = clock();
    std::cout << "MemCopy: " << (end - begin) * 1000 / CLOCKS_PER_SEC << " ms" << std::endl; 
    begin = clock();
    for (int i=0; i<10 ; i++)
        ProcessCopySharedMemory(l_UI32_Size);
    end = clock();
    std::cout << "ReadProcessMemory: " << (end - begin) * 1000 / CLOCKS_PER_SEC << " ms" << std::endl; 

    for (int i=0; i<10 ; i++)
        CopySharedMemory2(l_UI32_Size);

    delete l_pShm;
    return 0;
}

这是输出:

MemCopy: 8891 ms
ReadProcessMemory: 6068 ms

FirstCopy: 796 ms
SecondCopy: 327 ms
FirstCopy: 795 ms
SecondCopy: 328 ms
FirstCopy: 780 ms
SecondCopy: 344 ms
FirstCopy: 780 ms
SecondCopy: 343 ms
FirstCopy: 780 ms
SecondCopy: 327 ms
FirstCopy: 795 ms
SecondCopy: 343 ms
FirstCopy: 780 ms
SecondCopy: 344 ms
FirstCopy: 796 ms
SecondCopy: 343 ms
FirstCopy: 796 ms
SecondCopy: 327 ms
FirstCopy: 780 ms
SecondCopy: 328 ms

如果有人知道为什么 memcpy 这么慢,如果有解决这个问题的方法,我会洗耳恭听。

谢谢。

最佳答案

我的评论作为引用答案。

在大块内存中使用“memcpy”需要操作系统为每个复制的新页面筛选其进程/内存表。反过来,使用“ReadProcessMemory”直接告诉操作系统应该将哪些页面从哪个进程复制到哪个其他进程。

当您使用单个页面进行基准测试时,这种差异消失了,确认了其中的一些。

我猜想“memcpy”在“小型”场景中速度更快的原因可能是“ReadProcessMemory”有一个从用户模式到内核模式的额外切换。另一方面,Memcpy 将任务卸载到底层内存管理系统,该系统始终与您的进程并行运行,并且在某种程度上由硬件本地支持。

关于c++ - ReadProcessMemory 比 SharedMemory 上的 memcpy 更快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13525462/

有关c++ - ReadProcessMemory 比 SharedMemory 上的 memcpy 更快的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  3. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  4. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby-on-rails - Ruby - 如何从 ruby​​ 上的 .pfx 文件中提取公钥、rsa 私钥和 CA key - 2

    我有一个.pfx格式的证书,我需要使用ruby​​提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o

  8. 带有 attr_accessor 的类上的 Ruby instance_eval - 2

    我了解instance_eval和class_eval之间的基本区别。我在玩弄时发现的是一些涉及attr_accessor的奇怪东西。这是一个例子:A=Class.newA.class_eval{attr_accessor:x}a=A.newa.x="x"a.x=>"x"#...expectedA.instance_eval{attr_accessor:y}A.y="y"=>NoMethodError:undefinedmethod`y='forA:Classa.y="y"=>"y"#WHATTT?这是怎么回事:instance_eval没有访问我们的A类(对象)然后它实际上将它添加到

  9. ruby-on-rails - rails 上的 ruby : radio buttons for collection select - 2

    我有一个集合选择:此方法的单选按钮是什么?谢谢 最佳答案 Rails3中没有这样的助手。在Rails4中,它是collection_radio_buttons. 关于ruby-on-rails-rails上的ruby:radiobuttonsforcollectionselect,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/18525986/

  10. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

随机推荐