有没有办法检测 Linux 上的内存碎片?这是因为在一些长时间运行的服务器上,我注意到性能下降,并且只有在重新启动进程后才能看到更好的性能。在使用 Linux 大页面支持时我更能注意到这一点——Linux 中的大页面是否更容易产生碎片?
我特别研究过/proc/buddyinfo
。我想知道是否有更好的方法(不仅仅是 CLI 命令本身,任何程序或理论背景都可以)来查看它。
答案1
我正在回答Linux的标签。我的回答仅针对Linux。
是的,大页面更容易产生碎片。内存有两种视图,一种是进程获得的(虚拟的),另一种是内核管理的(真实的)。页面越大,与其邻居分组(并保持在一起)就越困难,尤其是当您的服务运行在还必须支持其他服务的系统上时,这些服务默认分配和写入的内存比它们实际使用的内存要多得多。
内核对(实际)授予地址的映射是私有的。用户空间看到它们就像内核呈现它们一样,这是有充分理由的,因为内核需要能够过度使用而不会混淆用户空间。您的进程会获得一个良好、连续的“迪士尼化”工作的地址空间,而不管内核实际上是什么正在做带着那段幕后的记忆。
您在长时间运行的服务器上看到性能下降的原因很可能是因为没有明确锁定(例如mlock()
/mlockall()
或posix_madvise()
)并且在一段时间内没有修改的分配块已被分页输出,这意味着您的服务在必须读取它们时会转到磁盘。修改此行为使您的流程变得坏邻居,这就是为什么许多人将 RDBMS 放在与 web/php/python/ruby/whatever 完全不同的服务器上。解决该问题的唯一方法是减少对连续块的竞争。
只有当页面 A 在内存中而页面 B 已移至交换区时,碎片化才会真正明显(在大多数情况下)。当然,重新启动服务似乎可以“解决”这个问题,但这只是因为内核尚未有机会在其过量使用率范围内将进程(现在)新分配的块移出页面。
事实上,在高负载下重新启动(假设)“apache”可能会将其他服务拥有的块直接发送到磁盘。所以是的,“apache”会在短时间内有所改善,但“mysql”可能会受到影响……至少在内核因缺乏足够的物理内存而使它们同样受到影响之前。
添加更多内存,或分拆要求苛刻的malloc()
消费者:)您需要关注的不仅仅是碎片。
尝试vmstat
了解实际存储在哪里的内容。
答案2
核心
要获取当前碎片索引使用:
cat /sys/kernel/debug/extfrag/extfrag_index
要对内核内存进行碎片整理,请尝试执行:
sysctl vm.compact_memory=1
您还可以尝试关闭透明大页面(又名 THP)和/或禁用交换(或减少swappiness
)。
用户空间
为了减少用户空间碎片,你可能需要尝试不同的分配器,例如jemalloc
(它有很好的自省能力,它将为您提供分配器内部碎片的内部信息)。
您可以通过重新编译程序或直接使用以下命令运行程序来切换到自定义 malloc LD_PRELOAD
:(LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app
请注意THP 与内存分配器之间的交互)
虽然与内存碎片略微无关(但与内存压缩/迁移相关),但您可能希望运行服务的多个实例,每个 NUMA 节点一个,并使用绑定它们numactl
。
答案3
使用大页面不应导致 Linux 上出现额外的内存碎片;Linux 对大页面的支持仅限于共享内存(通过 shmget 或 mmap),任何使用的大页面都必须由系统管理员专门请求和预分配。一旦进入内存,它们就会被固定在那里,不会被换出。在内存碎片的情况下换入大页面的挑战正是它们留在内存中的原因(当分配 2MB 大页面时,内核必须找到 512 个连续的空闲 4KB 页面,而这些页面可能根本不存在)。
有关大页面的 Linux 文档: http://lwn.net/Articles/375098/
有一种情况,内存碎片可能会导致大页面分配缓慢(但不会导致大页面原因内存碎片化)是内存碎片化的一种表现形式,前提是您的系统配置为在应用程序请求时增加大页面池。如果 /proc/sys/vm/nr_overcommit_hugepages 大于 /proc/sys/vm/nr_hugepages,则可能会发生这种情况。
答案4
有,/proc/buddyinfo
这很有用。如果输出格式好,效果会更好,就像这个 Python 脚本可以做到的那样:
https://gist.github.com/labeneator/9574294
对于大页面,您需要一些 2097152 (2MiB) 或更大的空闲片段。对于透明大页面,当内核被要求提供一些时,它将自动压缩,但如果您想查看可以获得多少,请以 root 身份运行:
echo 1 | sudo tee /proc/sys/vm/compact_memory
没错,大页面会导致碎片化问题。要么您无法获得任何大页面,要么它们的存在导致内核花费大量额外时间来尝试获取一些大页面。
我有一个适合自己的解决方案。我在几台服务器和我的笔记本电脑上使用它。它对虚拟机非常有用。
将该选项添加kernelcore=4G
到 Linux 内核命令行。在我的服务器上,我使用 8G。请谨慎使用这个数字,因为它会阻止内核分配该内存之外的任何内容。需要大量套接字缓冲区或将磁盘写入流式传输到数百个驱动器的服务器不会喜欢这样的限制。任何必须为 slab 或 DMA“固定”的内存分配都属于此类别。
然后,您的所有其他内存都变为“可移动”,这意味着它可以被压缩成适合大页面分配的块。现在透明大页面可以真正起飞并按预期工作。每当内核需要更多 2M 页面时,它只需将 4K 页面重新映射到其他地方即可。
而且,我不太确定这与零拷贝直接 IO 有何关联。“可移动区域”中的内存不应该被固定,但直接 IO 请求对于 DMA 来说正是如此。它可能会复制它。它可能会将它固定在可移动区域中。无论哪种情况,它可能都不是您想要的。