聊聊C语言中的malloc申请内存的内部原理
发布时间:2025-05-12 20:26:02 发布人:远客网络
一、聊聊C语言中的malloc申请内存的内部原理
深入解析 C语言中 malloc函数的内部工作原理
在深入探讨 malloc函数的内部工作原理之前,让我们先了解一下它在现代编程语言中的作用。现代语言通常在应用层实现内存分配器,这些分配器模仿内核的 SLAB分配器,预先从操作系统申请内存并构建内存池。当我们需要内存时,分配器直接从内存池中提供,而当我们释放内存时,分配器负责管理内存,并通过策略决定是否将其回收给操作系统。这种方法既能灵活管理不同大小的内存对象,又能避免频繁调用 mmap系统调用带来的开销。常见的内存分配器包括 glibc的 ptmalloc、Google的 tcmalloc和 Facebook的 jemalloc等。
我们将以经典的 ptmalloc分配器为例,详细介绍 malloc函数的内部工作原理。这里,我们将使用 glibc源码,下载地址为:ftp.gnu.org/gnu/glibc/。我们使用的是版本 2.12.1。
ptmalloc分配器通过多个分配区 arena进行内存管理。arena支持多个分配区,以降低多线程操作时的锁开销。每个分配区包含一个锁,用于处理内存申请竞争。arena的数据结构定义在 struct malloc_state中,包含锁、内存管理数据结构和 next指针,用于链接所有分配区。
分配区中的基础内存分配单位是 malloc_chunk,简称 chunk。它包含 header和 body部分。每次申请内存时,分配器都会分配一个合适的 chunk给用户,返回 body部分的地址供用户使用。释放内存时,chunk不会被操作系统回收,而是由分配器管理,body部分的 fd、bk字段用于双向链表操作。
ptmalloc通过 fastbins、smallbins、largebins和 unsortedbins管理空闲内存块。fastbins用于快速分配小内存,smallbins、largebins和 unsortedbins使用 bins数组管理。top chunk用于在所有 bins都无法满足需求时尝试分配。
在 malloc的工作过程中,分配器根据内存大小在 fastbins、bins、smallbins、largebins和 unsortedbins中查找合适的 chunk。释放内存时,将 chunk放回相应的管理链表。此外,分配器还会处理 chunk的拆分和合并,以优化内存管理。
了解这些原理后,我们再来看看 malloc函数在 glibc中的实现。在 public_mALLOc函数中,主要处理分配区和锁操作以避免冲突。核心逻辑在 _int_malloc函数中,它包含了分配尝试和操作系统内存申请的处理。在尝试过程中,可能会涉及到 chunk的切分和合并,以减少内存碎片。
以上内容详细介绍了 C语言中 malloc函数的内部工作原理。为了更深入地了解相关技术,我们还上线了一系列技术视频,内容涵盖硬件原理、内存管理、进程管理、文件系统、网络管理、容器底层原理、Golang语言运行时、性能观测和性能优化等多个方面。欢迎访问我们的开发内功修炼视频上线页面,了解更多详情,并关注公众号「开发内功修炼」以获取更多技术资讯。
二、C语言 malloc
1、在C和C++语言中,malloc函数用于向系统申请分配指定大小的内存空间。其函数声明为void*malloc(int size),返回类型为void*,即未确定类型的指针。void*可以强制转换为任何其他类型的指针。
2、与new相比,malloc有两点不同。首先,new返回指定类型的指针,并且可以自动计算所需大小。例如:
3、int*p; p= new int;返回类型为int*类型(整数型指针),分配大小为sizeof(int);
4、int* parr; parr= new int[100];返回类型为int*类型(整数型指针),分配大小为sizeof(int)* 100。
5、而malloc则需要我们自己计算需要的字节数,并且在返回后强行转换为实际类型的指针。例如:
6、int* p; p=(int*) malloc(sizeof(int));
7、如果写成p= malloc(sizeof(int));,程序将无法通过编译,因为void*不能直接赋值给int*类型变量,所以必须通过(int*)进行强制转换。
8、其次,函数的实参应为sizeof(int),用于指明一个整型数据需要的大小。如果写成int* p=(int*) malloc(1);,代码虽然能通过编译,但事实上只分配了1个字节大小的内存空间。当你往里存入一个整数,就会有3个字节无家可归,造成原有数据内容全部被清空。
9、尽管malloc无法直接分配出一个new[]效果,即一段连续的内存,但通过指定你需要的内存大小,也可以实现类似的效果。例如:
10、int* p=(int*) malloc(sizeof(int)* 100);分配可以放得下100个整数的内存空间。
11、malloc只能分配内存,不能对所得的内存进行初始化,因此得到的新内存中的值将是随机的。
12、除了分配和最后释放的方法不同,通过malloc或new得到的指针在其他操作上保持一致。例如:
13、char*ptr; if((ptr=(char*)malloc(0))== NULL) puts("Got a null pointer"); else puts("Got a valid pointer");
14、此时得到的是Got a valid pointer。把0赋给malloc能得到一个合法的指针。
三、malloc函数的用法 C语言malloc函数的使用
1、工具/原料:Microsoft Visual Studio 2010。
3、在 malloc的使用.c文件中包含各种需要用到的头文件。
5、定义一个指针p,将其初始化为NULL。
7、其中 sizeof(int)*100代表你要申请的内存空间的大小(可以自己随意设置)。
8、因为malloc函数的返回值是void*,而p是int*,所以要对返回值进行强制转换。
9、再编写一些代码来判断一下malloc是否申请内存成功,接着按快捷键F5运行,查看输出结果,可以看到内存申请成功。
10、最后,我们还要用free函数释放掉刚申请的内存,防止内存泄露,至此,整个代码编写完成。