C 通过运行程序检查堆空间的大小;与实际边界不匹配
我需要知道为进程分配的堆空间量。理论上,在我的代码中,只调用malloc(1)(在C程序中)一次就可以得到堆的起始地址。并调用sbrk(0)一个系统调用,返回分配给该进程的堆端空间。下面是我的测试代码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
#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