首页 文章

堆内存和平板分配

提问于
浏览
6

我对 heapfree list 很困惑 . 我有几个问题,我对malloc如何在C中工作有我自己的理解 . 如果我错了,请纠正我 .

  • 堆内存是否组织为数据块的链表(空闲列表)?

  • 堆内存和空闲列表之间有区别吗?

我对存储分配的理解(可以改进): - 当我们调用malloc时,它会在堆中分配内存,并通过从 free list 中选择合适大小的数据块来实现,对吧?

当malloc返回某个特定的内存块时,它将从空闲列表中删除,并在页表中更新该内存块的物理地址 .

当使用 free() 释放内存时,数据块将插回到空闲列表中,并可能减少碎片,与相邻块结合,并清除页表条目中的 present 位 .

因此整个堆是一个自由列表(空闲块的链表)分配的数据块 .

这是存储分配的全面情况吗?

编辑:来自Linux内核开发(Robert Love)关于内存管理的章节, Slab allocation

“一个空闲列表包含一个已经分配的可用数据结构块 . 当代码需要一个新的数据结构实例时,它可以从空闲列表中获取一个结构,而不是分配足够的内存并设置它以后,当不再需要数据结构时,它将返回到空闲列表而不是取消分配 . 从这个意义上说,空闲列表充当对象缓存,缓存常用类型的对象 . “

自由列表被称为“可用的,已分配的数据结构块” .

  • 当它在自由列表中时它是如何 allocated 的?

  • 如何将一块内存返回到空闲列表_ not _与解除分配该块一样?

  • How is slab allocation different from storage allocation

3 回答

  • 0

    这里指的是两个不同的分配器,

    • Buddy系统分配器,用于将页面分配给Zone,使用free_list存储空闲页面,在释放后分配它们,如果可能的话,将它们组合回一个更高级别的更大的连续页面大小 .

    • Slab分配器,用于已经分配的数据结构,如keme_cache,kmalloc调用 .

    引用Heap Memory in C Programming表示堆 .

    对于用户空间中的c程序,我们在call_stack中有malloc发生的堆内存 . 这由_break标记,当需要更多内存时,由sbrk()提升 .

    在Linux内核中,每个进程都有task_struct,它有自己的堆栈和指向它所使用的页面列表的指针 .

  • 6

    您要做的第一件事是区分内核和程序分配 . 就像@Wyzard所说,malloc使用brk(sbrk,有时是mmap)从内核中获取更多页面 . 我对malloc的理解非常好,但它跟踪你可能称之为竞技场的东西 . 它调解对内存的访问,并根据需要进行适当的系统调用以分配内存 .

    空闲列表是管理内存的一种方法 . 每次从内核需要更多内存时调用mmap或brk都是缓慢且低效的 . 这两个都需要上下文切换到内核模式,并将分配数据结构来跟踪哪个进程拥有内存 . 用户级别的空闲列表是一种不经常请求并将内存返回内核的优化 . 用户程序的目标是完成其工作,而不是等待内核完成其工作 .

    现在回答你的其他问题:

    • 当它在自由列表中时如何分配?

    另一种考虑自由列表的方法是作为缓存 . 程序将发出请求,内核将尝试按需实现它们,而不是一次性完成它们 . 但是,当一个程序用一块内存完成时,快速路径不是将它返回给内核,而是将它放在安全的地方再次分配 . 特别是,一个空闲列表可以跟踪分配器可以从中获取的内存区域,但是以这种方式(具有内存保护)这样做,用户代码不能仅仅选择它并开始写入所有内容区域 . .

    • 如何将一块内存返回到空闲列表与释放该块不一样?

    如果我们假设真正解除分配块需要将其返回到内核并让它更新其内部页表,那么差异实际上在于对底层物理页(或帧)的控制 . 实际上释放内存并将内存返回到内核意味着现在内核可以从这些页面中提取,而将其返回到用户级别的空闲列表意味着程序的某些部分仍然控制着该内存 .

    • slab分配与存储分配有何不同?

    这开始得到一些不同的领域(我并不十分熟悉) . slab分配器是内核管理内存分配的一种方式 . 从我所看到的,slab尝试将分配分组为不同的大小,并有一个页面池满足这些要求 . 我相信常见的x86架构将允许以16字节到4 MB的两个幂来分配连续的物理内存(尽管我在64位机器上) . 我相信在这个级别上有一些自由列表的概念,以及有效升级或降级分配大小以满足不同系统需求的方法 .

    另一方面,存储分配听起来像确保硬盘上有空间 . 我实际上没有听过这个词,所以我只能推测 .

  • 2

    malloc() 与页表实际上没有关系;它分配虚拟地址,内核负责跟踪页面实际存储在物理RAM或磁盘上的位置 .

    malloc() 通过 brk() 系统调用与内核交互,该调用要求内核为进程分配更多页面,或者将页面释放回内核 . 所以实际上有两个级别的内存分配:

    • 内核将页面分配给进程,使这些页面不可供其他进程使用 . 从内核_402458的角度来看,它是一个连续的虚拟地址空间 . brk() 操作的"program break"是内核允许您访问的地址之间的边界(因为它们对应于已分配的页面)以及如果您尝试访问它们将导致分段错误的地址 .

    • malloc() 分配程序的可变大小部分's data segment for use by the program. When there'在数据段的当前大小内没有足够的可用空间,它使用 brk() 从内核获取更多页面,使数据段更大 . 当它发现数据段末尾的某些空间未被使用时,它使用 brk() 将未使用的页面返回给内核,从而使数据段更小 .

    请注意,即使在该进程中运行的程序实际上没有使用任何页面,也可以将页面分配给进程(由内核) . 如果 free() 是位于数据段中间的内存块,则 free() 的实现不能使用 brk() 来缩小数据段,因为在更高的地址处仍有其他已分配的块 . 因此,从内核的角度来看,页面仍然分配给您的程序,即使它们是从 malloc() 立场开始的"free space" .

    你对自由列表如何工作的描述听起来对我来说是正确的,尽管我在谈论Linux内核中的内存分配,这与用户空间进程中 malloc() 的内存分配无关 . 这种免费列表可能有不同的作用 .

相关问题