【问题标题】:does brk and sbrk round the program break to the nearest page boundary?brk 和 sbrk 是否将程序四舍五入到最近的页面边界?
【发布时间】:2021-04-03 00:16:34
【问题描述】:

根据我的教科书,我的问题正如蒂蒂所说的那样

int brk(void *end_data_segment);

brk() 系统调用将程序中断设置为 end_data_segment。由于虚拟内存是以页为单位分配的, end_data_segment 有效地向上舍入到下一页边界。

并且由于在 Linux 上,sbrk() 是作为使用 brk() 系统调用的库函数实现的,所以我希望这两个函数都会将程序中断舍入到下一页边界。但是当我在 x86_64 Linux 机器(ubuntu)上进行测试时,事实证明这两个函数都将程序中断移动到所要求的确切位置(我尝试使用 brk,结果是一样的)。

    int main(int argc, char *argv[])
    {
       void *ori = sbrk(100);
       printf("original program break at %p\n", ori);
       void *now = sbrk(0);
       printf("program break now at %p\n", now);
      return 0;
  }

这是输出

original program break at 0x56491e28f000
program break now at 0x56491e28f064

那么这里发生了什么?

【问题讨论】:

  • is effectively rounded up 不代表“会回来”,

标签: linux dynamic-memory-allocation sbrk


【解决方案1】:

brk 分配/释放页面。然而,基于虚拟内存操作系统中内存管理的最小数据单元是页面这一事实的实现细节对调用者是透明的。

在 Linux 内核中,brk 保存未对齐的值,并使用对齐的值来确定是否需要分配/释放页面:

asmlinkage unsigned long sys_brk(unsigned long brk)
{
[...]
    newbrk = PAGE_ALIGN(brk);
    oldbrk = PAGE_ALIGN(mm->brk);
    if (oldbrk == newbrk)
        goto set_brk;
[...]
    if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
        goto out;
set_brk:
    mm->brk = brk;
[...]
}

至于sbrk:glibc 调用brk 并在用户空间中维护当前程序中断(__curbrk)的(未对齐)值:

void *__curbrk;
[...]
void *
__sbrk (intptr_t increment)
{
  void *oldbrk;
  if (__curbrk == NULL || __libc_multiple_libcs)
    if (__brk (0) < 0)          /* Initialize the break.  */
      return (void *) -1;
  if (increment == 0)
    return __curbrk;
  oldbrk = __curbrk;
[...]
  if (__brk (oldbrk + increment) < 0)
    return (void *) -1;
  return oldbrk;
}

因此,sbrk 的返回值不会反映 Linux 内核中发生的页面对齐。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多