【问题标题】:Why does calling sbrk(0) twice give a different value?为什么调用 sbrk(0) 两次会给出不同的值?
【发布时间】:2019-06-15 02:58:20
【问题描述】:

我试图理解sbrk() 函数。

据我所知:
sbrk(0) 返回中断的当前地址并且不增加它。
sbrk(size) 将中断的地址增加size 字节并返回之前的地址休息时间。

所以我创建了一些东西来测试它:

#include <unistd.h>
#include <stdio.h>

int main(void)
{
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x
    printf("sbrk(5) = %p\n", sbrk(5)); // should return value x
    printf("sbrk(0) = %p\n", sbrk(0)); // should return value x + 5
}

所以我希望看到这样的结果:

sbrk(0) = 0x1677000 // x value
sbrk(0) = 0x1677000 // x value
sbrk(5) = 0x1677000 // x value
sbrk(0) = 0x1677005 // x value + 5

但我却得到了这个:

sbrk(0) = 0x1677000 // x value
sbrk(0) = 0x1698000 // y value
sbrk(5) = 0x1698000 // y value
sbrk(0) = 0x1698005 // y value + 5

为什么sbrk(0) 的前两个调用不返回相同的值? 这两个更改中断地址的调用之间会发生什么?

编辑: 将地址存储在变量中解决了这个问题:

int main(void)
{
    void *toto1 = sbrk(0);
    void *toto2 = sbrk(0);
    void *toto3 = sbrk(5);
    void *toto4 = sbrk(0);

    printf("sbrk(0) = %p\n", toto1);
    printf("sbrk(0) = %p\n", toto2);
    printf("sbrk(5) = %p\n", toto3);
    printf("sbrk(0) = %p\n", toto4);
}

【问题讨论】:

  • printf 可能会使用一些动态内存。尝试将值分配给变量并立即打印它们。
  • 那么请用其他代码更新你的问题,所以没有人会重复这个假设。
  • 您需要使用多个变量,并在调用printf之前对sbrk进行全部调用。您更新的代码与第一个基本相同,并且会遇到同样的问题。
  • 我的猜测是标准 I/O 部分的初始化是延迟完成的。也就是说,在需要时进行初始化,其中一部分初始化是为stdout 分配缓冲区。
  • 这里是glibc的参数处理代码:github.com/bminor/glibc/blob/master/stdio-common/…它在几个地方调用malloc()

标签: c memory sbrk brk


【解决方案1】:

您的程序执行以下调用序列:

sbrk()
printf()
sbrk()
printf()
...

第一次调用printf 在内部调用mallocstdout 分配一个缓冲区(stdout 默认情况下是行缓冲的,但缓冲区是在您第一次打印到它时按需创建的)。

这就是第二次调用 sbrk 返回不同值的原因。

This answer 没有直接关系,但是来自 valgrind 的错误消息暴露了隐藏在 printf 中的底层 malloc 调用的存在。)

您的第二个示例预先执行了所有 sbrk 调用,因此其他函数在您背后调用 malloc 并没有什么意外。

【讨论】:

    猜你喜欢
    • 2020-10-14
    • 2014-02-24
    • 1970-01-01
    • 2019-04-22
    • 2012-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多