C 通过运行程序检查堆空间的大小;与实际边界不匹配

C 通过运行程序检查堆空间的大小;与实际边界不匹配,c,memory,malloc,heap,heap-memory,C,Memory,Malloc,Heap,Heap Memory,我需要知道为进程分配的堆空间量。理论上,在我的代码中,只调用malloc(1)(在C程序中)一次就可以得到堆的起始地址。并调用sbrk(0)一个系统调用,返回分配给该进程的堆端空间。下面是我的测试代码 #include <stdlib.h> #include <stdio.h> #include <unistd.h> #ifndef ALLOCATE_BYTES #define ALLOCATE_BYTES 0x1000000 #endif /* #ifnd

我需要知道为进程分配的堆空间量。理论上,在我的代码中,只调用malloc(1)(在C程序中)一次就可以得到堆的起始地址。并调用sbrk(0)一个系统调用,返回分配给该进程的堆端空间。下面是我的测试代码

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

#ifndef ALLOCATE_BYTES
#define ALLOCATE_BYTES 0x1000000
#endif /* #ifndef ALLOCATE_BYTES */

void subroutine (void);
int main()
{
    void *init_ptr = malloc((size_t) 1);
    void *end_ptr = sbrk((intptr_t) 0);

    printf(" Total Heap space = %lld B = %lld kB  \n", 
    (long long) (init_ptr - end_ptr),
    (long long) (init_ptr - end_ptr)/1024);

    subroutine();

    end_ptr = sbrk((intptr_t) 0); /* New edit 1 */
    printf(" Total Heap space = %lld B = %lld kB  \n", 
    (long long) (init_ptr - end_ptr),
    (long long) (init_ptr - end_ptr)/1024);

    return 0;
}


void subroutine (void)
{
    void *ptr;
    long long count = 0;
    size_t size = ALLOCATE_BYTES;
    size_t size_p = ALLOCATE_BYTES + 1;
    long long mem_alocated = 0;

    printf("  start rate to %u  \n", size);
    while (1)
    {
    ptr = malloc((size_t)size);

    if (ptr != NULL)
    {
        mem_alocated += size;
        count++;
    }

    if ((ptr == NULL) && (size == size_p))
    {
        size/=2;
        printf("overflow --> reduced Bytes SIZE %*u & "
        "current count = %lld ---> total bytes %lld \n"
        , 7, size, count, mem_alocated);
    }

    if ((ptr == NULL) && (size == 1))
    {
        printf("overflow....!! at %lld for %lld bytes\n", 
        count, count * ALLOCATE_BYTES);
        break;
    }
    size_p = size;
    }
}
这个结果表明我有“135160字节”的堆内存位置。但是如果我开始使用所有的函数,直到重复的
malloc()
函数调用返回
NULL
。在这样做的同时,我会记录我的程序现在消耗了多少字节的内存

但这里的问题是,我的理论堆空间(135160字节)与实际计数(3386638336字节)不匹配。我遗漏了什么吗

编辑2:
我通过
malloc()
调用添加了一些指针返回检查,并将其聚合以查看总数。我观察到分配的总字节数刚好小于我的理论堆空间。这意味着两件事
malloc()
在内部不调用
sbrk()
,其次是在别处分配内存。直到这一点我还是对的,还是这里缺少了什么?

你完全误解了
brk
/
sbrk
<代码>sbrk(0)将显示当前程序中断的位置,即数据段的结束。当malloc空间不足时,它将调用带有正偏移量的
sbrk
,该偏移量将调整数据段的大小,从而进一步移动程序中断。委员会澄清了这一点:

描述

brk()和sbrk()更改程序中断的位置 定义进程数据段的结束(即程序中断 是未初始化数据段结束后的第一个位置 (修订)增加程序中断会产生分配内存的效果 对过程的认识;减少中断会释放内存。

brk()将数据段的结尾设置为addr指定的值, 当该值合理时,系统具有足够的内存,并且 进程未超过其最大数据大小(请参阅setrlimit(2))

sbrk()按增量字节递增程序的数据空间。Call- 可以使用递增为0的ing sbrk()来查找电流 程序中断的位置

(强调矿山)


此外,通常在现代malloc实现中,足够大小(比如>128kB)的分配直接分配给数据段外部的
mmap
。我要测试从
malloc(65536)
返回的指针是否在初始化数据段中的地址之间(执行全局
intfoo=42;
,然后
&foo
应该在
.bss
/未初始化数据之前)当前程序中断。

您完全误解了
brk
/
sbrk
<代码>sbrk(0)将显示当前程序中断的位置,即数据段的结束。当malloc空间不足时,它将调用带有正偏移量的
sbrk
,该偏移量将调整数据段的大小,从而进一步移动程序中断。委员会澄清了这一点:

描述

brk()和sbrk()更改程序中断的位置 定义进程数据段的结束(即程序中断 是未初始化数据段结束后的第一个位置 (修订)增加程序中断会产生分配内存的效果 对过程的认识;减少中断会释放内存。

brk()将数据段的结尾设置为addr指定的值, 当该值合理时,系统具有足够的内存,并且 进程未超过其最大数据大小(请参阅setrlimit(2))

sbrk()按增量字节递增程序的数据空间。Call- 可以使用递增为0的ing sbrk()来查找电流 程序中断的位置

(强调矿山)


此外,通常在现代malloc实现中,足够大小(比如>128kB)的分配直接分配给数据段外部的
mmap
。我要测试从
malloc(65536)
返回的指针是否在初始化数据段中的地址之间(执行全局
intfoo=42;
,然后
&foo
应该在
.bss
/未初始化数据之前)当前的程序中断。

我想你没有记住的是,你的“实际计数”是系统上可用的RAM,用于多种用途。例如,我将您的程序修改为:

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

#ifndef ALLOCATE_BYTES
#define ALLOCATE_BYTES 0x1000000
#endif /* #ifndef ALLOCATE_BYTES */

int main()
{
    void *init_ptr = malloc((size_t) 1);
    void *end_ptr = sbrk((intptr_t) 0);

    printf("\nmalloc returned: 0x%08x\n", (uint64_t)init_ptr);
    printf("sbrk returned: 0x%08x\n", (uint64_t)end_ptr);

    printf(" Total Heap space = %lld B = %lld kB  \n", 
    (long long) (end_ptr - init_ptr),
    (long long) (end_ptr - init_ptr)/1024);

    sleep(300);

    return 0;
 }
现在,从这里您可以看到,当前堆从0x01cac000开始,运行到0x01ccd000。请注意,malloc不会从堆的开头开始分配内存

另外,请注意,堆可以向上增长,直到它撞到加载动态库的区域(在本例中,这是0x7f16a2e44000)

从上面的内存映射列表中,您还可以看到堆栈的位置(如果您对此感兴趣),以及程序的各个部分的加载位置。您可以使用
readelf
实用程序确定这些块是什么,您可以看到:

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
  INTERP         0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0008d4 0x0008d4 R E 0x200000
  LOAD           0x000e10 0x0000000000600e10 0x0000000000600e10 0x000248 0x000250 RW  0x200000
  DYNAMIC        0x000e28 0x0000000000600e28 0x0000000000600e28 0x0001d0 0x0001d0 RW  0x8
  NOTE           0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x0007a8 0x00000000004007a8 0x00000000004007a8 0x000034 0x000034 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x000e10 0x0000000000600e10 0x0000000000600e10 0x0001f0 0x0001f0 R   0x1
从这里可以看出,从0x00400000到0x00401000的内存区域被第二个程序头描述的文件内容所占用。此段包含以下程序部分:
.interp
.note.ABI标记
.note.gnu.build id
.gnu.hash
.dynsym
.dynstr
.gnu.version
.gnu.version\co
******@crossbow:~/junk$ ./temp &
[2] 2069
******@crossbow:~/junk$ 
malloc returned: 0x01cac010
sbrk returned: 0x01ccd000
 Total Heap space = 135152 B = 131 kB  
******@crossbow:ps
  PID TTY          TIME CMD
 1681 pts/0    00:00:00 bash
 1775 pts/0    00:00:15 emacs
 2069 pts/0    00:00:00 temp
 2070 pts/0    00:00:00 ps
******@crossbow:~/junk$ cat /proc/2069/maps
       00400000-         00401000 r-xp 00000000 fc:02 10616872                   /home/******/junk/temp
       00600000-         00601000 r--p 00000000 fc:02 10616872                   /home/******/junk/temp
       00601000-         00602000 rw-p 00001000 fc:02 10616872                   /home/******/junk/temp
       01cac000-         01ccd000 rw-p 00000000 00:00 0                          [heap]
   7f16a2e44000-     7f16a2fff000 r-xp 00000000 fc:02 70779581                   /lib/x86_64-linux-gnu/libc-2.19.so
   7f16a2fff000-     7f16a31fe000 ---p 001bb000 fc:02 70779581                   /lib/x86_64-linux-gnu/libc-2.19.so
   7f16a31fe000-     7f16a3202000 r--p 001ba000 fc:02 70779581                   /lib/x86_64-linux-gnu/libc-2.19.so
   7f16a3202000-     7f16a3204000 rw-p 001be000 fc:02 70779581                   /lib/x86_64-linux-gnu/libc-2.19.so
   7f16a3204000-     7f16a3209000 rw-p 00000000 00:00 0 
   7f16a3209000-     7f16a322c000 r-xp 00000000 fc:02 70779574                   /lib/x86_64-linux-gnu/ld-2.19.so
   7f16a3407000-     7f16a340a000 rw-p 00000000 00:00 0 
   7f16a3428000-     7f16a342b000 rw-p 00000000 00:00 0 
   7f16a342b000-     7f16a342c000 r--p 00022000 fc:02 70779574                   /lib/x86_64-linux-gnu/ld-2.19.so
   7f16a342c000-     7f16a342d000 rw-p 00023000 fc:02 70779574                   /lib/x86_64-linux-gnu/ld-2.19.so
   7f16a342d000-     7f16a342e000 rw-p 00000000 00:00 0 
   7ffcee9ab000-     7ffcee9cc000 rw-p 00000000 00:00 0                          [stack]
   7ffcee9ef000-     7ffcee9f1000 r-xp 00000000 00:00 0                          [vdso]
   7ffcee9f1000-     7ffcee9f3000 r--p 00000000 00:00 0                          [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                          [vsyscall]
Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
  INTERP         0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x0008d4 0x0008d4 R E 0x200000
  LOAD           0x000e10 0x0000000000600e10 0x0000000000600e10 0x000248 0x000250 RW  0x200000
  DYNAMIC        0x000e28 0x0000000000600e28 0x0000000000600e28 0x0001d0 0x0001d0 RW  0x8
  NOTE           0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x0007a8 0x00000000004007a8 0x00000000004007a8 0x000034 0x000034 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x000e10 0x0000000000600e10 0x0000000000600e10 0x0001f0 0x0001f0 R   0x1