如何在不为其分配内存的情况下将缓冲区传递给 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()的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用循环的情况下将json分配给另一个[重复]

如何在不使用向量的情况下将数组传递给函数?

如何在不复制的情况下将画布 imageData 传递给 emscripten c++ 程序?

如何在不循环的情况下将数组(Range.Value)传递给本机 .NET 类型?

如何在不使用角度的ng的情况下将输入值从父组件传递给子组件?

如何在不覆盖 TTY 的情况下将密码传递给 su/sudo/ssh?