当前位置:  开发笔记 > 运维 > 正文

在没有memcpy的情况下连接两个内存缓冲区

如何解决《在没有memcpy的情况下连接两个内存缓冲区》经验,为你挑选了2个好方法。

在CI中有一个函数foo(char*),它接受一个内存指针.在调用者中,我有两个不同的内存缓冲区,我需要连接,所以我可以传递一个指针foo().有没有办法让我这样做而不实际将一个缓冲区复制到另一个缓冲区的末尾而不改变foo()本身?即使两个缓冲区显示为foo()的一个虚拟连续缓冲区

出于性能原因,我需要这个.O(n)解决方案(其中n是缓冲区长度之一)对我的情况是不可接受的.此外,Linux特定的解决方案很好,如果它有帮助.

谢谢.尼尔



1> jfs..:

是的,有一种方法.

为缓冲区分配内存,使它们在内存中相邻.

例:

char* a = malloc(a_size + b_size);
char* b = a + a_size;



2> bk1e..:

这个问题似乎要问是否可以将两个缓冲区(A和B)的内容与以下约束连接起来:

您无法复制A或B的内容.

你不能改变A的地址.

该操作必须具有最差情况复杂度

据推测,B的地址是A和B尚未连接的地址.(正如JF Sebastian在他的回答中指出的那样,如果你能够首先连续分配A和B,那么你已经完成了.但这似乎是一种堕落的情况.)

您必须能够从Linux内核驱动程序执行此操作(请参阅Jerome的答案下的评论).

A和B都不是页面对齐的(参见原始问题下的评论).

A和B都不是页面大小的倍数(请参阅原始问题下的评论).

鉴于这一切,我的答案是否定的:这是不可能的.

是的,OS内核可以使用CPU的MMU(内存管理单元,在具有一个内存的架构上)重新映射内核虚拟地址空间或用户虚拟地址空间中的内存.分配一个连续的虚拟地址空间块,然后通过修改虚拟地址空间块的页表条目以指向A和B的物理地址,将A和B重新映射到该缓冲区.

这不会更改A本身的虚拟地址(因为旧的虚拟地址仍然有效),但它确实要求您通过不同的虚拟地址访问它.这可能是个问题.

今天典型CPU架构上的这种重新映射的粒度基于页面大小,并且由于A和B不是页面对齐的,也不是页面大小的倍数,因此您将无法使它们完全对齐.这绝对是个问题.

重新映射N个字节需要为每M个字节修改至少一个页表条目,其中M是页面大小.这意味着重映射操作无论如何都具有O(n)的计算复杂度.其他操作(例如为页表分配更多物理页面,刷新高速缓存和TLB等)会产生额外的性能影响.

另外,我想知道这个问题的目标是否涉及DMA(直接内存访问).使用需要连续内存的旧设备执行DMA时,除非您拥有IOMMU,否则无需重新映射数量.一个可以进行分散 - 聚集DMA的现代设备首先不需要连续的缓冲区.

推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有