如何在不为其分配内存的情况下将缓冲区传递给 write()
Posted
技术标签:
【中文标题】如何在不为其分配内存的情况下将缓冲区传递给 write()【英文标题】:How to pass a buffer to write() without allocating memory for it 【发布时间】:2013-06-06 09:35:21 【问题描述】:这个问题很难表达,但我会尝试。 我想测试我的 USB 连接的性能,因此我在一个嵌入式设备上使用 gadgetfs,所以我可以只写一个文件描述符并将数据发送到主机。 但是当我想发送大量数据时,我无法分配尽可能多的数据。
write(int fildes, const void *buf, size_t nbyte);
有没有办法将指针传递到内存中可以实际读取 nbyte
字节的某个位置?
我无法分配我想要发送的大小的数组或向量。因为我收到“无法分配内存”错误。
【问题讨论】:
你能少分配一点,然后循环发送吗?或者这在您使用的环境中是不可能的?它需要是一次写入吗? 如果您可以使用多个写入调用,则分配较小的内存(尽可能),然后在循环中多次发送相同的数据.. 这样您就可以通过单次分配来分析写入速度.. 【参考方案1】:如果您的操作系统有MAP_ANONYMOUS
或/dev/zero
,那么您可以将mmap
放入您的虚拟地址空间,直至最大可能映射并从那里读取。
#include <sys/mman.h>
void * zeroed_memory = mmap(NULL, nbytes, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
这会将长度为nbytes
的连续映射分配到单个归零的只读页面,因此实际上不使用任何物理内存。你可以读取整个数组(并且只会得到零),但你不能写入它。
尽管由于物理硬件限制,大多数系统都会限制您的最大连续虚拟映射。当前的 x86_64 Linux 一般支持 64TB 长映射。
注意:某些系统(例如 OS X,可能其他基于 BSD 的系统有 MAP_ANON
而不是 MAP_ANONYMOUS
,请咨询 man 2 mmap
以找出确切的系统)。
如果您的系统不支持MAP_ANONYMOUS
,但/dev/zero
是,那么等效方法是:
void * zeroed_memory;
int fd = open("/dev/zero", O_RDONLY);
if (fd > 0)
zeroed_memory = mmap(NULL, nbytes, PROT_READ, MAP_PRIVATE, fd, 0);
【讨论】:
【参考方案2】:write
函数将获取您提供的任何地址,并(尝试)从该地址开始写入 nbyte
字节。只要可以读取内存,这应该可以正常工作。
如果您要发送超过几千字节的数据,通常最好以相对较小的大小(例如 4KB)进行多次写入,并使用循环来完成写入。
【讨论】:
问题是,出于某种原因,我必须(主机端)阅读我在小工具上执行的每个write()
。因此,当我循环写入时,主机必须先读取 4 个字节,然后我才能调用下一个 write()
。
您是说如果您从目标发送 1MB,主机必须将其读取为单个 1MB 读取,否则它将“跳过”数据?这对我来说似乎很奇怪。但是是的,最终会在某个时候或另一个地方出现一些阻塞,您需要等待另一端“赶上”。这就是我建议一次 4KB 的原因,作为一次写一个单词和数百 KB 或 MB 之间的一个很好的折衷。不确定您实际期望的其他答案 - 我认为没有其他解决方案。
如果写入的数据重复,我可能会建议使用writev()
。您可以多次指定 iovec 指向同一个缓冲区。
writev
仅在您想多次写入相同的数据时才有帮助。 OP 不清楚这是否是愿望。
@Hasturkun 这实际上帮了很多忙!因为我想测试性能,所以我不在乎我实际发送了什么数据。谢谢!以上是关于如何在不为其分配内存的情况下将缓冲区传递给 write()的主要内容,如果未能解决你的问题,请参考以下文章
如何在不复制的情况下将画布 imageData 传递给 emscripten c++ 程序?
如何在不循环的情况下将数组(Range.Value)传递给本机 .NET 类型?