我最近了解了GCC的一些C库内存管理功能的内置函数,特别是__builtin_malloc()
和相关的内置函数(参见https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html })。在了解__builtin_malloc()
之后,我想知道如何提供相对于普通malloc()
相关库例程的性能改进。
例如,如果函数成功,则必须提供一个可以通过调用plain free()
释放的块,因为指针可能被没有__builtin_malloc()
编译的模块释放或者启用__builtin_free()
(或者我错了,如果使用__builtin_malloc()
,必须全局使用内置函数?)。因此,分配的对象必须是可以使用malloc()
和free()
处理的数据结构来管理的。
我无法找到有关__builtin_malloc()
如何工作或其确切工作方式的任何细节(我不是编译器开发人员,因此通过GCC源代码进行探索并不是我的驾驶室)。在我尝试直接调用__builtin_malloc()
的一些简单测试中,它最终只是作为对普通malloc()
的调用而在目标代码中发出。但是,在这些简单的测试中,我可能没有提供细微或平台细节。
通过调用普通__builtin_malloc()
,malloc()
可以提供哪些性能改进? __builtin_malloc()
是否依赖于glibc malloc()
实现使用的相当复杂的数据结构?或者相反,glibc的malloc()
/ free()
是否有一些代码来处理可能由__builtin_malloc()
分配的块?
基本上,它是如何运作的?
答案 0 :(得分:33)
我认为__builtin_malloc()
没有特殊的海湾合作委员会内部实施。相反,它仅作为内置存在,因此可以在某些情况下进行优化。
举个例子:
#include <stdlib.h>
int main(void)
{
int *p = malloc(4);
*p = 7;
free(p);
return 0;
}
如果我们禁用内置函数(使用-fno-builtins
)并查看生成的输出:
$ gcc -fno-builtins -O1 -Wall -Wextra builtin_malloc.c && objdump -d -Mintel a.out
0000000000400580 <main>:
400580: 48 83 ec 08 sub rsp,0x8
400584: bf 04 00 00 00 mov edi,0x4
400589: e8 f2 fe ff ff call 400480 <malloc@plt>
40058e: c7 00 07 00 00 00 mov DWORD PTR [rax],0x7
400594: 48 89 c7 mov rdi,rax
400597: e8 b4 fe ff ff call 400450 <free@plt>
40059c: b8 00 00 00 00 mov eax,0x0
4005a1: 48 83 c4 08 add rsp,0x8
4005a5: c3 ret
按预期发出对malloc
/ free
的来电。
但是,允许malloc
是内置的
$ gcc -O1 -Wall -Wextra builtin_malloc.c && objdump -d -Mintel a.out
00000000004004f0 <main>:
4004f0: b8 00 00 00 00 mov eax,0x0
4004f5: c3 ret
所有main()
都被优化了!
基本上,通过允许malloc
成为内置函数,如果从不使用结果,GCC可以自由地消除调用,因为没有其他副作用。
同样的机制允许将printf
的“浪费”通话更改为对puts
的通话:
#include <stdio.h>
int main(void)
{
printf("hello\n");
return 0;
}
内置禁用:
$ gcc -fno-builtin -O1 -Wall builtin_printf.c && objdump -d -Mintel a.out
0000000000400530 <main>:
400530: 48 83 ec 08 sub rsp,0x8
400534: bf e0 05 40 00 mov edi,0x4005e0
400539: b8 00 00 00 00 mov eax,0x0
40053e: e8 cd fe ff ff call 400410 <printf@plt>
400543: b8 00 00 00 00 mov eax,0x0
400548: 48 83 c4 08 add rsp,0x8
40054c: c3 ret
内置启用:
gcc -O1 -Wall builtin_printf.c && objdump -d -Mintel a.out
0000000000400530 <main>:
400530: 48 83 ec 08 sub rsp,0x8
400534: bf e0 05 40 00 mov edi,0x4005e0
400539: e8 d2 fe ff ff call 400410 <puts@plt>
40053e: b8 00 00 00 00 mov eax,0x0
400543: 48 83 c4 08 add rsp,0x8
400547: c3 ret