【问题标题】:Allocating largest buffer without using swap在不使用交换的情况下分配最大缓冲区
【发布时间】:2011-03-15 19:06:18
【问题描述】:

在 Linux 下的 C/C++ 中,我需要分配一个大(数 GB)内存块,以便存储来自连接到以太网端口的传感器的实时数据和大约 110MB/s 的流数据。我想分配尽可能多的内存,以最大化我可以存储的数据序列的长度。但是,我还需要确保不会发生磁盘交换,因为由此产生的磁盘访问延迟和有限带宽会导致传感器(非常有限)的缓冲区溢出。

确定要分配多少内存的最佳方法是什么?我是否仅限于分配比报告的可用内存略小的块,还是可以更直接地与 linux 虚拟内存管理器交互?

【问题讨论】:

  • 纯粹出于兴趣,您使用的是什么传感器?
  • @Space_C0wb0y:这不是真的。
  • 获得更好的传感器。或切换到适当的实时操作系统。虚拟内存操作系统不会让你做你想做的事,除非你做一些奇怪的事情,比如使用 ram 磁盘作为交换空间。我在 IDE 接口的另一侧看到了 4GB 以上的 RAM。适当供电的 RAM。非常快。对于颠覆基于虚拟内存的操作系统并将其全部缓存在 RAM 中非常有用。
  • @Chris Becke:Linux 不会强迫你做任何奇怪的事情来使缓冲区不可交换。有一个简单的系统调用可以将它们锁定到物理内存中,或者如果需要,您可以将系统配置为完全没有交换磁盘。而且我发现它的实时行为对于几毫秒或更长时间的实时约束非常令人满意。

标签: c++ c linux virtual-memory


【解决方案1】:

如果计算机系统专门用于从您的传感器接收数据,您可以简单地禁用交换。然后分配尽可能大的缓冲区,在系统中留出足够的内存仅用于基本工具。

【讨论】:

  • 遗憾的是它不是一个专用系统。但是,它有足够的 RAM 用于其他用途,因此禁用交换可能是一种选择。
  • 检查一段时间的内存使用情况。您可能会看到交换几乎从未使用过,除非某些应用程序开始疯狂地泄漏内存。我一直在运行无交换的桌面系统,没有任何问题。但是对于更通用的解决方案,请按照 Luther 的建议使用 mlock(2)。并且不要将所有内容都分配为一个连续的缓冲区。内存管理器可能在分配(或重新分配)它时遇到问题。使用通过某个接口链接到一个的许多较小的缓冲区。这样你可以例如在运行时调整缓冲区大小。
  • 为“buffor”拼写点赞:P!
【解决方案2】:

好吧,在 linux 下,您可以使用 mlock()/mlockall() 将地址范围保留在物理内存中并防止它被换出。使用 mlock 的过程需要一些特权才能做到这一点,“man mlock”有详细信息。我不确定最大 mlock'able 块(它可能与看似“免费”的块不同),所以可能二进制搜索可能会有所帮助(锁定一个范围,如果失败减少区域的大小等。)

另一方面,对于固态驱动器来说,110MB/s 并不是真正的问题。具有 280MB/s 写入速度的 60GB SSD 售价约为 200 美元。只需将传感器数据复制到一个小的写入缓冲区并将其流式传输到 SSD。

【讨论】:

    【解决方案3】:

    确定分配多少内存的最佳方法是什么?

    由于虚拟内存的使用方式,不可交换的内核内存,几乎不可能确定应用程序可以访问多少已安装的内存。

    我能想到的最好办法是允许用户配置用于缓冲的内存量。

    我是否仅限于分配比报告的可用内存略小的块,

    报告的可用内存并不是真正的“可用物理内存”。很遗憾。

    或者我可以更直接地与 linux 虚拟内存管理器交互吗?

    这可以通过使用自定义设备驱动程序、直接在内核空间中分配内存并通过mmap() 提供对它的访问来完成。一般不推荐,但可以在特殊情况下使用,例如您的情况。

    但是,我还需要确保不会发生磁盘交换

    随着 Linux 内核开发的步伐,知识很快就过时了,所以请谨慎对待我在此所说的话。您可以尝试使用以下内容:

    1. SysV 共享内存。一般不换。见man shmget

    2. tmpfs - 内存文件系统。至少在早期的 2.6 内核中,内存被固定到 RAM,因此不可交换。要将其用作内存,请在 tmpfs 上创建一个文件,write() 在文件中添加一些内容(以强制实际分配内存),然后 mmap() 文件。

    【讨论】:

    • 只是为了记录,tmpfs 实际上是可交换的。还有另一个变种 rootfs 永远不会被交换。但正因为如此,你必须非常小心,不要过度强调它。
    【解决方案4】:

    如果您malloc 所需的内存量并以该速度写入,由于所有页面错误(即将虚拟内存的每一页映射到物理内存,也可能包括换出其他进程的内存)。

    为了避免这种情况,您可以在开始从传感器读取之前将整个分配的缓冲区memset 设置为 0,以便将所有需要的虚拟内存映射到物理内存。

    如果你只使用可用的物理内存,你应该不会遭受任何交换。使用更多会导致其他进程的内存被交换到磁盘 - 如果这些进程空闲,它不应该造成任何问题。如果它们处于活动状态(即偶尔使用它们的内存),则会发生一些交换 - 可能以比硬盘驱动器带宽低得多的速率。您使用的内存越多,将换出更多活动进程的内存,并且会发生更多的 HD 活动 - 此时,您可以使用的最大内存量与良好的性能几乎是反复试验的结果。

    如果使用超过可用物理内存,肯定会导致内存写入速率发生交换,并且无法避免。

    【讨论】:

    • 没有必要使用memset() 来欺骗系统分配物理内存。使用mlock() 明确地执行此操作,并确保它永远不会被换出。
    猜你喜欢
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    • 2015-01-05
    • 1970-01-01
    • 2017-03-24
    • 2021-08-31
    • 2013-06-14
    相关资源
    最近更新 更多