当前位置:首页 > 内存 > 正文

malloc从哪里分配内存

  • 内存
  • 2024-08-27 23:38:26
  • 8793

一、Linux内存管理(三)--内存分配之malloc本文将探讨Linux中动态内存分配的基本机制,特别是malloc函数的运行原理。开源社区提供了丰富的内存分配器,其中glibc中的ptmalloc2就是基于dlmalloc的一个例子,并且提供了多线程支持。malloc的源代码在文件glibc-2.37\malloc\malloc.c中,它实际上指的是别名__libc_malloc的内部实现。
动态内存的分配主要通过两个系统调用:mmap和brk。当所需的内存量超过预定义的限制(默认128KB)时,将使用mmap分配,否则使用brk分配。该策略旨在平衡系统调用冗余和内存分配效率。
为了提高效率,malloc实际上是利用池化的思想来预先分配较大的内存块,以便在后续请求中直接使用,避免重复的系统调用。这个过程涉及到使用多种底层数据结构,包括arena、maloc_state、heap_info、chunk等。
竞技场用于表示连续堆场区域,分为主竞技场和客观竞技场。mainarena作为全局变量存在于数据段中,不需要维护多个堆,并且可以通过sbrk扩展堆段。当内存耗尽时,mainarena可以通过sbrk或mmap扩展堆段以满足映射的内存段。另一方面,限制线的码数以减少负荷。当线程数量超过arena数量时,arena共享开始。
Heap_info用于存储堆元数据,当线程竞技场中的堆空间耗尽时,将向线程竞技场分配新的堆。段是描述内存分配的基本单位,包括段大小、先前段状态信息和对齐要求。
关于内存组织,chunk有很多种类型,包括已分配chunk、空闲chunk、topchunk和剩余chunk。Topchunk位于arena的顶部,用于处理所有盒子中都没有找到合适的空闲内存的情况。当上半部分的大小不合适时,会通过系统调用进行拆分或扩展。
关于freechunk、brk和mmap管理的详细解释将在后续文章中深入讨论。有关内存管理的更多信息,请参阅《嵌入式Linux笔记》专栏。引用时请注明出处。
二、15+张图剖析内存分配之malloc详解malloc用于内存分配的详细解释

malloc函数的复杂性导致直接分析源码比较困难,但是我们可以关注一下过程。首先,了解Malloch分配的内存结构很重要。当我们使用malloc时,分配的内存不仅仅是用户请求的内存量,还带有管理头和尾部。


在内存分配示例中,用户指定0x100字节,实际分配的填充空间包括系统配置的cookie和填充空间。填充区域上方和下方都有空格,用于区分可用内存和不可用内存以及返回时越界。修正由上部空间的7个连续位置组成。


在进入程序之前,系统会创建一个堆空间来管理内存,并通过__cdecl_heap_init函数构建一个包含16个HEADER节点的链表,每个节点控制1MB内存。每个节点将1MB划分为32个32KB段,并保存一个代表尚未分配的虚拟地址的pHeapData指针。


再深入一点,在pRegion表示的标记区域结构中,每个内存段(组)有8个4KB的内存页,可用的内存被加载到一个链表中。分配时,从附加的内存列表中查找,如果没有找到,则扩展到其他连接的列表中。返回时,通过比较地址范围来确定组成员,并通过合并空闲内存和更新分配时间来进行操作。


如果一个Group被完全回收,它不会立即返回到系统,而是等待其他Group被重用后再合并和释放。这消除了与操作系统的冗余交互并提高了效率。


三、malloc和new的区别是什么?

mallok和new的区别有四点:请求的内存位置、返回类型的安全性、内存分配失败时的返回值、是否需要指定内存大小。

1.请求的内存位置不同

新的处理程序从空闲存储区域(freestore)动态为对象分配内存空间。空闲存储区域是C++中基于new运算符的抽象概念每当通过new运算符创建内存申请时,内存就是空闲存储区域。

malloc函数从堆中动态分配内存。堆是操作系统中的一个术语,它是操作系统维护的一种特殊内存,用于动态内存分配C语言程序使用malloc从堆中分配内存,使用free释放分配的相应内存。

2.返回类型安全性不同

当new运算符内存分配成功时,返回一个对象类型指针,且类型与对象实际匹配,不需要进行类型转换,因此new是一个类型安全运算符。

如果malloc内存分配成功,会返回void*。void*指针需要通过强制类型转换转换为我们需要的类型。

3.内存分配失败时的返回值不同

当新的内存分配失败时,会抛出bac_alloc异常,并且不会返回NULL。

malloc分配内存失败时返回NULL。

4.是否需要指定不同的内存大小?

使用new运算符申请内存分配时,不需要指定内存块大小,编译器会根据类型信息自动计算。

malloc需要显式声明所需的内存大小。

参考资料:—malloc和new的区别