0

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

类似地,堆地址趋于“向下”增长......但我如何才能确定我的计算机上的地址是增加还是减少?

4

2 回答 2

2

Mac OS X 上的手册页说:

brksbrk函数是在虚拟内存管理出现之前的早期遗留下来的历史奇闻。

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

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

假设您使用:

void *base = sbrk(1024);

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

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

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

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

于 2014-01-28T08:17:43.887 回答
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

在第 1 处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 并继续进行 2nd 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 并继续进行 3rd 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()foo().

我在我的终端上得到0x7fffa6d60ba0和作为第一个和第 1001 个递归调用的地址。它们现在都属于该区域(; 0x7e2000 == 8 MB)。但请注意,它以前是; 0x21000 == 132 KB。0x7fffa6582ff0buffoo()[stack]7fffa6582000-7fffa6d640007fffa6d43000-7fffa6d64000

$ 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);
于 2014-01-28T10:12:49.190 回答