C:sbrk()地址是上升还是下降?

时间:2014-01-28 07:41:55

标签: c unix memory-management heap sbrk

当sbrk()返回指向作为堆开头的地址的指针时,地址是升序还是降序?例如,如果我有一个来自地址1到10的10字节堆,那么sbrk()会返回指向地址10或1的指针吗?

在类似的说明中,堆地址往往会“向下”增长......但是如何判断地址是否在我的计算机上增加或减少?

2 个答案:

答案 0 :(得分:2)

Mac OS X上的手册页说:

  

brksbrk函数是前几天遗留下来的历史好奇心        虚拟内存管理的出现。

     

sbrk(0)可以可靠地返回程序中断的当前值。

     

sbrk函数返回指向基数的指针        新的存储如果成功;否则为-1,errno设置为表示分配失败的原因。

假设您使用:

void *base = sbrk(1024);

之后,假设没有错误,base将包含1024字节(最小)内存块的起始地址; (char *)base + 1024将超出您的要求,但由于页面大小可能大于1024,因此它可能仍然有效。

它没有直接说明后续分配是否会有比另一个更大或更小的地址。但是,它可能会按地址递增顺序排列。

  

brk()函数设置a的中断或最低地址        进程的数据段(未初始化的数据)到addr(紧接在bss之上)。数据寻址        被限制在addr和指向堆栈段的最低堆栈指针之间。内存由页面大小的brk分配;如果addr不能被系统页面大小整除,那么        增加到下一页边界。

这意味着额外的空间位于数据和bss段之后,并朝向堆栈(在内存中向下增长)增长。但是,依靠这可能是愚蠢的。在调用sbrk(0)以获得额外空间后,您最好使用sbrk(extra)来建立当前结束;这将告诉你你真正得到了什么,这两个地址告诉你它在哪里可用。

答案 1 :(得分:0)

如果您使用的是Linux,则可以检查/proc/$PID/maps以查看虚拟地址空间如何用于每个进程。

示例代码:mappingTest.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int foo(int depth) {
    char buf[8192];
    if (0 == depth)
        printf("%p\n", buf);
    if (1000 < depth) {
        printf("%p\n", buf);
        return getchar();
    } else {
        return 1 + foo(depth + 1);
    }
}

int main() {
    const size_t SIZE = 1000 * 1000 * 1000;
    getchar();
    char * const p = malloc(SIZE);
    printf("%p\n", p);
    getchar();
    free(p);
    getchar();
    foo(0);
    return 0;
}

注意:char buf[8192]1000次递归假设最大堆栈大小为8 MB(您可以使用ulimit -s确认。)

$ gcc mappingTest.c -o mappingTest -Wall -Wextra -Wno-missing-field-initializers -std=c89 -O0 -g3 && echo OK
OK
$ ./mappingTest

在第一个getchar(),我们看到了该过程的以下内存映射:

$ cat /proc/`pidof mappingTest`/maps
00400000-00401000 r-xp 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00600000-00601000 r--p 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00601000-00602000 rw-p 00001000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
7f2e96e8a000-7f2e9703f000 r-xp 00000000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9703f000-7f2e9723f000 ---p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9723f000-7f2e97243000 r--p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97243000-7f2e97245000 rw-p 001b9000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97245000-7f2e9724a000 rw-p 00000000 00:00 0
7f2e9724a000-7f2e9726c000 r-xp 00000000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e97443000-7f2e97446000 rw-p 00000000 00:00 0
7f2e97469000-7f2e9746c000 rw-p 00000000 00:00 0
7f2e9746c000-7f2e9746d000 r--p 00022000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e9746d000-7f2e9746f000 rw-p 00023000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffa6d43000-7fffa6d64000 rw-p 00000000 00:00 0                          [stack]
7fffa6dff000-7fffa6e00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

我们按Enter键继续进行第二次getchar()

我在终端上获得0x7f2e5b4dd010作为p的值,并且它属于下面列表中的第一个匿名映射区域7f2e5b4dd000-7f2e96e8a000,但它在上面不存在列表。

$ cat /proc/`pidof mappingTest`/maps
00400000-00401000 r-xp 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00600000-00601000 r--p 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00601000-00602000 rw-p 00001000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
7f2e5b4dd000-7f2e96e8a000 rw-p 00000000 00:00 0
7f2e96e8a000-7f2e9703f000 r-xp 00000000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9703f000-7f2e9723f000 ---p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9723f000-7f2e97243000 r--p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97243000-7f2e97245000 rw-p 001b9000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97245000-7f2e9724a000 rw-p 00000000 00:00 0
7f2e9724a000-7f2e9726c000 r-xp 00000000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e97443000-7f2e97446000 rw-p 00000000 00:00 0
7f2e97468000-7f2e9746c000 rw-p 00000000 00:00 0
7f2e9746c000-7f2e9746d000 r--p 00022000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e9746d000-7f2e9746f000 rw-p 00023000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffa6d43000-7fffa6d64000 rw-p 00000000 00:00 0                          [stack]
7fffa6dff000-7fffa6e00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

我们按Enter键进入第3 getchar()

在下面的列表中,我们看到匿名映射区域因free()而消失。

$ cat /proc/`pidof mappingTest`/maps
00400000-00401000 r-xp 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00600000-00601000 r--p 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00601000-00602000 rw-p 00001000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
7f2e96e8a000-7f2e9703f000 r-xp 00000000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9703f000-7f2e9723f000 ---p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9723f000-7f2e97243000 r--p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97243000-7f2e97245000 rw-p 001b9000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97245000-7f2e9724a000 rw-p 00000000 00:00 0
7f2e9724a000-7f2e9726c000 r-xp 00000000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e97443000-7f2e97446000 rw-p 00000000 00:00 0
7f2e97468000-7f2e9746c000 rw-p 00000000 00:00 0
7f2e9746c000-7f2e9746d000 r--p 00022000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e9746d000-7f2e9746f000 rw-p 00023000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffa6d43000-7fffa6d64000 rw-p 00000000 00:00 0                          [stack]
7fffa6dff000-7fffa6e00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

我们按Enter键进入getchar()深度嵌套调用中的第4个foo()

我的终端上有0x7fffa6d60ba00x7fffa6582ff0作为buf的第1和第1001递归调用中foo()的地址。它们都属于[stack]区域(7fffa6582000-7fffa6d64000; 0x7e2000 == 8 MB)。但请注意,它之前是7fffa6d43000-7fffa6d64000; 0x21000 == 132 KB。

$ cat /proc/`pidof mappingTest`/maps
00400000-00401000 r-xp 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00600000-00601000 r--p 00000000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
00601000-00602000 rw-p 00001000 08:05 21687266                           /home/nodakai/prog/exp/mappingTest
7f2e96e8a000-7f2e9703f000 r-xp 00000000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9703f000-7f2e9723f000 ---p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e9723f000-7f2e97243000 r--p 001b5000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97243000-7f2e97245000 rw-p 001b9000 08:05 14314431                   /lib/x86_64-linux-gnu/libc-2.15.so
7f2e97245000-7f2e9724a000 rw-p 00000000 00:00 0
7f2e9724a000-7f2e9726c000 r-xp 00000000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e97443000-7f2e97446000 rw-p 00000000 00:00 0
7f2e97468000-7f2e9746c000 rw-p 00000000 00:00 0
7f2e9746c000-7f2e9746d000 r--p 00022000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7f2e9746d000-7f2e9746f000 rw-p 00023000 08:05 14314443                   /lib/x86_64-linux-gnu/ld-2.15.so
7fffa6582000-7fffa6d64000 rw-p 00000000 00:00 0                          [stack]
7fffa6dff000-7fffa6e00000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

您可以使用这样的内联汇编获得更多乐趣:

#define PEEK_ESP(reg)          \
   __asm__ __volatile__ (      \
       "movq %%rsp, %0"        \
       : "=r"(reg)             \
   )
...
void *p;
PEEK_ESP(p);