当memcpy()比memmove()更快时,真正的重要案例是什么?

sha*_*oth 16 c c++ memory memcpy memmove

memcpy()和源之间的关键区别memmove()是,memmove()当源和目标重叠时,它将正常工作.当缓冲区肯定不重叠时,memcpy()更可取,因为它可能更快.

困扰我的是这个潜在的.它是一种微观优化还是存在真正重要的例子,当memcpy()我们真的需要使用memcpy()而不是坚持memmove()到处时?

Mat*_*ner 19

memmove()如果编译器无法推断出无法重叠,则至少有一个隐式分支可以向前或向后复制.这意味着,如果没有能力有利于优化memcpy(),memmove()是至少由一个分支比较慢,并且通过内联指令以处理各种情况下(如果内联是可能的)占用的任何额外的空间.

读取eglibc-2.11.1两者的代码memcpy()memmove()确认这是怀疑的.此外,在向后复制期间不可能进行页面复制,只有在没有重叠的情况下才能获得显着的加速.

总之,这意味着:如果您可以保证区域不重叠,则选择memcpy()结束memmove()可避免分支.如果源和目标包含对应的页面对齐和页面大小的区域,并且不重叠,则某些体系结构可以为这些区域使用硬件加速副本,无论您是否调用memmove()memcpy().

Update0

除了我上面列出的假设和观察之外,实际上还有一个区别.从C99开始,这两个函数存在以下原型:

void *memcpy(void * restrict s1, const void * restrict s2, size_t n);
void *memmove(void * s1, const void * s2, size_t n);
Run Code Online (Sandbox Code Playgroud)

由于能够假设2个指针s1并且s2没有指向重叠的内存,因此直接的C实现memcpy能够利用它来生成更高效的代码而无需借助汇编程序,请参阅此处了解更多信息.我确信memmove可以做到这一点,但是在我看到的那些上面需要额外的检查eglibc,这意味着性能成本可能略高于这些功能的C实现的单个分支.


Mik*_*our 13

充其量,调用memcpy而不是memmove保存指针比较和条件分支.对于大型副本,这是完全无关紧要的.如果您正在做许多小型副本,那么可能值得衡量差异; 这是唯一可以判断它是否重要的​​方法.

它绝对是一种微观优化,但这并不意味着memcpy当您可以轻松证明它是安全的时候就不应该使用它.过早的悲观情绪是多恶的根源.