我正在使用sys_brk系统调用来动态分配堆中的内存。我注意到,在获取当前的休息位置时,我通常会得到与此相似的值:
mov rax, 0x0C
mov rdi, 0x00
syscall
结果
rax 0x401000
该值通常为512字节对齐。所以我想问一下中断值是否有一些对齐要求?或者我们可能会以我们想要的方式错位?
答案 0 :(得分:1)
内核 以字节粒度跟踪中断。但如果您完全关心性能,请不要将它直接用于小型分配。
关于内核将中断四舍五入到页面边界的评论中有一些讨论,但事实并非如此。 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;
将当前中断设置为传递给系统调用的确切arg(如果它有效)。如果当前中断始终是页面对齐的,则内核上不需要PAGE_ALIGN()
。
当然,内存保护至少具有页面粒度(如果内核选择使用匿名大页面进行此映射,则可能存在大页面)。所以you can access memory out to the end of the page containing the break without faulting。这就是为什么内核代码只是检查中断是否移动到另一个页面以跳过map / unmap逻辑,但仍然更新实际的brk。
AFAIK,什么都不会在中断之上使用映射内存作为临时空间,因此它不像堆栈指针下面的内存可以异步地被破坏。
brk
只是一个内核内置的简单内存管理系统。系统调用很昂贵,因此如果您关心性能,则应该在用户空间中跟踪事物,并且只在需要新页面时才进行系统调用。 直接使用sys_brk
进行微小分配对于性能来说非常糟糕,特别是在启用了Meltdown + Spectre缓解的内核中(使系统调用更加昂贵,如数万个时钟周期+ TLB和分支)预测失效,而不是数百个时钟周期。)