任何人都可以解释malloc()内部如何运作
我有时会这样做strace program,我看到很多sbrk系统调用,正在man sbrk讨论它的使用情况,malloc()但不多.
我在考虑Linux内核如何实现系统调用,我想知道是否有人可以给我一个关于sbrk/brk如何工作的高级视图?
我已经查看了内核代码,但是它有很多内容而且我不理解它.我希望得到某个人的摘要?
c代码:
// program break mechanism
// TLPI exercise 7-1
#include <stdio.h>
#include <stdlib.h>
void program_break_test() {
printf("%10p\n", sbrk(0));
char *bl = malloc(1024 * 1024);
printf("%x\n", sbrk(0));
free(bl);
printf("%x\n", sbrk(0));
}
int main(int argc, char **argv) {
program_break_test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译以下代码时:
printf("%10p\n", sbrk(0));
Run Code Online (Sandbox Code Playgroud)
我收到警告提示:
format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’
问题1:为什么?
在我之后malloc(1024 * 1024),程序突破似乎没有改变.
这是输出:
9b12000
9b12000
9b12000
Run Code Online (Sandbox Code Playgroud)
问题2:进程在启动以备将来使用时是否在堆上分配内存?或者编译器改变分配的时间点?否则,为什么?
[更新]摘要:brk()或mmap()
在查看TLPI并检查手册页(在TLPI的作者的帮助下)之后,现在我了解了如何malloc()决定使用brk()或mmap(),如下所示:
mallopt() …
我有一个自定义分配器函数,它使用sbrk()来获取内存.如何在不再需要时释放此内存?
malloc()是否有一个等效于free()的函数?
或者我是否必须使用brk()来设置数据段的结尾?
我遇到了_sbrk的问题.在编译的链接阶段,我使用下面的命令链接我的对象,我得到未定义的引用_sbrk.
arm-none-eabi-ld -static -T linkerscript.ld -o exe timer_example.o /home/ziga/projects/cs_lite/arm-none-eabi/lib/libc.a /home/ziga/projects/cs_lite/lib/gcc/arm-none-eabi/4.5.1/libgcc.a
Run Code Online (Sandbox Code Playgroud)
我正在为arm926ej-s编译并在ARM模式下,所以我想我选择了正确的multilib(libc.a和libgcc.a),它位于home/ziga/projects/cs_lite/arm-none-eabi/lib /文件夹中.
我一直在网上搜索_sbrk函数,它是某种内存管理调用,它不包含在标准C库中,因为它依赖于微处理器.所以我必须自己编写_sbrk函数吗?我该怎么做?你有arm926ej-s的例子吗?编写此函数后,我打算将其编译为目标文件,并将其与其他对象库连接在一起.
亲切的问候,Ziga.
我解决了这个问题并将在这里发布解决方案,所以我回馈社区.函数_sbrk位于ARM的NXP CDL包中.包可供下载(链接适用于所有不熟悉此功能的人):http: //www.lpclinux.com/Downloads/WebHome在子文件夹CDL_v005/csps/lpc313x/bsps/ea3131/source中,您将找到命名的源文件libnosys_gnu.c应该添加到项目中并编译到目标文件,之后链接到可执行文件以及其他对象和库.
祝愿和成功.
我正在努力理解这个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
}
Run Code Online (Sandbox Code Playgroud)
所以我期待看到如下结果:
sbrk(0) = 0x1677000 // x value
sbrk(0) = 0x1677000 // x value
sbrk(5) = 0x1677000 // x value
sbrk(0) = 0x1677005 // …Run Code Online (Sandbox Code Playgroud) 我在哪里可以sbrk()详细了解一下?
它是如何工作的?
在什么情况下我会想使用sbrk(),而不是繁琐的malloc()和new()?
顺便问一下,扩展是sbrk()什么?
虽然我知道Unix系统调用brk和函数的sbrk作用,但我不知道它们代表什么.任何人都可以开导我吗?
该手册页告诉我这么多,通过它我知道很多"的glibc"的内存管理的背景知识.
但我仍然感到困惑." malloc_trim(0) "(注意零作为参数)是什么意思(1.)"堆"部分中的所有内存都将返回给操作系统?或者(2.)只是堆的最顶层区域的所有"未使用"内存都将返回给操作系统?
如果答案是(1.),如果堆中仍然使用的内存怎么办?如果堆在某处使用了momery,它们会被删除,还是函数不能成功执行?
如果答案是(2.),那么那些地方而不是堆顶部的那些" 漏洞 "呢?它们已经是未使用的内存了,但仍然使用了堆的最顶层区域,这个调用会有效吗?
谢谢.
我在很多地方(MUSL邮件列表,MACOS论坛等)听说brk()和sbrk()不安全。这些地方中的许多要么根本不给出解释,要么给出非常模糊的解释。例如,此链接指出“这些功能从根本上被破坏了”,并继续说malloc和sbrk子系统被完全破坏了,它们破坏了堆,等等。
我的问题是:为什么会这样?如果malloc以这样的方式使用它来分配sbrk足够大的内存块,以平息或大大减少对进一步分配的需求,那么使用sbrk并且brk完全安全吗?
这是我sbrk和的实现brk:
sbrk:
#include <unistd.h>
#include <stddef.h>
void *sbrk(intptr_t inc)
{
intptr_t curbrk = syscall(SYS_brk, NULL);
if( inc == 0 ) goto ret;
if( curbrk < 0 ) return (void *)-1;
curbrk((void *)(curbrk+inc));
ret:
return (void *)curbrk;
}
Run Code Online (Sandbox Code Playgroud)
brk:
#include <unistd.h>
intptr_t brk(void *ptr)
{
if( (void *)syscall(SYS_brk, ptr) != ptr )
return -1;
else …Run Code Online (Sandbox Code Playgroud)