我正在使用 sys_brk 系统调用动态分配堆中的内存。我注意到,在获取当前中断位置时,我通常会得到与此类似的值:
mov rax, 0x0C
mov rdi, 0x00
syscall
结果
rax 0x401000
该值通常按 512 字节对齐。那么我想问一下break值有对齐要求吗?或者我们可以按照我们想要的方式错位它?
最佳答案
内核确实以字节粒度跟踪中断。但如果您非常关心性能,请不要直接将其用于小分配。
评论中有一些关于内核将中断舍入到页面边界的讨论,但事实并非如此。 The implementation of sys_brk
使用这个(添加了我的评论,因此脱离上下文才有意义)
newbrk = PAGE_ALIGN(brk); // the syscall arg
oldbrk = PAGE_ALIGN(mm->brk); // the current break
if (oldbrk == newbrk)
goto set_brk; // no need to map / unmap any pages, just update mm->brk
这会检查中断是否移动到不同的页面,但最终 mm->brk = brk;
将当前中断设置为传递给系统调用的确切参数(如果有效)。如果当前中断始终是页对齐的,则内核不需要 PAGE_ALIGN()
。
当然,内存保护至少具有页面粒度(如果内核选择使用匿名大页面进行此映射,则可能有大页面)。所以you can access memory out to the end of the page containing the break without faulting 。这就是为什么内核代码只是检查中断是否移动到不同的页面以跳过映射/取消映射逻辑,但仍然更新实际的 brk。
据我所知,没有任何东西会使用中断上方的映射内存作为暂存空间,因此它不像堆栈指针下方的内存可以异步破坏。
brk
只是内核中内置的一个简单的内存管理系统。系统调用的成本很高,因此如果您关心性能,您应该跟踪用户空间中的内容,并且仅在需要新页面时才进行系统调用。 直接使用sys_brk
进行微小分配对性能来说非常糟糕,特别是在启用了Meltdown + Spectre缓解功能的内核中(使系统调用更加昂贵,例如数万个时钟周期+ TLB 和分支预测失效,而不是数百个时钟周期)。
关于linux - sys_brk 的对齐要求是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48871138/