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

内存池实现(内存条可以8+16g混装吗)

  • 内存
  • 2024-08-01 10:57:23
  • 8740

一、malloc底层实现及原理

可以在对手方基础上实现,也可以在链表基础上实现

两者都扩展了brk堆的上限

Malloc使用使用了mmap的第二种使用方式(匿名)映射)。

1)当开放空间小于128K时,将调用brk()函数。malloc的基本实现是brk()系统调用函数,本质上是移动_enddata指针(其中_enddata时指的是Linux地址空间中堆段的结束地址,而不是数据段的结束地址)。

2)当打开空间大于128K时,mmap()系统调用函数在虚拟地址空间(堆和栈之间,称为“文件映射区域”)寻找空间打开。

Malloc函数用于动态分配内存,为了减少内存碎片和系统调用的开销,malloc使用内存池,它首先将一大块内存作为堆来应用,然后进行划分。将堆划分为多个内存块,以块为内存管理的基本单位,malloc会直接从堆中分配,使用隐式链表结构将堆划分为不同大小的连续块,包括已分配块和未分配块。同时,malloc使用显式链表结构来管理所有空闲块,这意味着使用双向链表将空闲块连接起来,每个空闲块记录一个相邻的、未分配的地址。

分配内存时,Malloc会通过隐式链表浏览所有空闲块,选择符合分配要求的块;合并内存时,malloc使用边界标记方法来确定每个块的大小,并根据前后块是否已分配来决定是否执行块合并。

1.空闲存储空间被组织为空闲链接列表(升序地址)。每个块包含一个长度、一个指向下一个块的指针以及一个指向其自己的存储空间的指针。(由于程序中某些位置可能无法通过malloc调用来申请,因此malloc管理的空间不一定是连续的。)
2.当应用程序请求到来时,malloc会扫描空列表,直到找到一个。块足够大(首先调整)(因此每个malloc调用不会花费相同的时间)。
3.如果该块与请求的大小匹配,则将其从链表中删除并返回给用户。如果块太大,则将其分为两部分,尾部部分交给用户,其余部分留在空列表中(标头信息更改)。因此,malloc分配一段连续的内存。
4.发布时,首先搜索空闲链接列表,找到可以插入已发布块的合适位置。如果空闲块的任一侧都是空闲块,则这两个块将被组合成一个更大的块,以减少内存碎片。

因为brk、sbrk和mmap都是系统调用。如果每次注册内存的时候都调用这三个命令,每次都会产生系统调用,会影响性能。这样很容易产生碎片,因为堆是从低地址到高地址的,如果高地址的内存不释放,那么低地址的内存就无法回收。
所以malloc使用的是内存池管理方式(ptmalloc)。ptmalloc使用边界标记方法将内存划分为多个块来管理内存分配和回收。为了提高malloc内存分配函数的效率,ptmalloc会提前向操作系统请求一部分内存供用户使用。当我们请求和释放内存时,ptmalloc会管理内存并使用多种策略来确定是否将其回收给操作系统。这样做的最大好处是可以帮助用户更有效地注册和释放内存,避免过多的内存碎片。


二、Python如何进行内存管理

Python中的内存管理一般看三个方面:

1)对象引用计数机制(自增4、自减5)

2)垃圾收集机制(手动和自动),分代回收)

3)内存池机制(大m,小p)

1)对象引用计数机制

跟踪内存对象,Python使用一种称为引用计数的简单技术。count(a)可以让你看到一个对象的引用计数,但是它比正常计数大1,因为调用函数时传递了a,所以a的引用计数增加了1。

2)垃圾收集机制

吃多了总会发胖,Python也是如此。随着Python的对象越来越多,它们占用的内存也越来越多。但你不必太担心Python的大小。在适当的时候,它会被“压垮”,开始垃圾收集,并删除过时的对象。

基本原理是,在Python中,当一个对象的引用计数降至零时,指向该对象的引用将被删除。None,意味着该对象成为垃圾并被回收。

例如,当一个新对象被分配了一个引用时,该对象的引用计数变为1。当删除引用并且对象的引用计数达到零时,可以对对象进行垃圾回收。

但是减肥是昂贵且困难的。在垃圾收集期间,Python无法执行任何其他操作。频繁的垃圾回收显着降低了Python的运行效率。如果内存中没有很多对象,则无需一直启动垃圾收集。

因此,Python仅在特定条件下才会自动启动垃圾回收。Python运行时,会记录对象分配(object
allocation)和对象释放(objectdeallocation)的次数。如果两者之间的差值高于某个阈值,就会触发垃圾收集。

可以通过gc模块中的get_threshold()方法查看阈值。

3)内存池机制

Python分为大内存和小内存:(256K是大内存和小内存的限制)

1.分配malloc的内存使用情况

2.小内存是使用内存池来分配的。

Python有两套内存管理机制的实现。一种是针对小物体。也就是说,如果大小小于256K,pymalloc会从内存池中申请内存空间,如果大于256K,则直接运行系统的malloc操作来申请内存空间。


三、TLSF——一种简单高效的内存池实现

探索实时系统内存管理新进展:TLSF——一种简单高效的内存池实践


在追求系统性能极致的领域,TLSF——一种方法专为实时而设计系统设计的动态内存分配器以其独特的设计理念脱颖而出。核心思想是优化内存分配和释放性能,特别是显着减少内存碎片和系统调用开销。它受到C++标准库中mallocAPI的启发,但更深入地实现了Arena优化策略。


关键的内存管理策略包括SequentialFit、SegreeratedFreeLists、BuddySystems和IndexedFit,每种策略都旨在在不同的复杂程度下提供高效的内存分配。SequentialFit流畅如水,时间复杂度为O(N),而SegreeratedFreeLists则凭借大小范围分类和分割实现了近乎实时的O(1)或O(M)复杂度。BuddySystems和IndexedFit分别通过logN效率展示了它们在管理大内存块方面的优势。


TLSFArena有明确的设计目标,追求实时系统环境中内存分配和释放的O(1)复杂度,同时显着减少内存碎片。巧妙的数据结构包括SegregedList和PhysicalList两层,共同维护FreeBlock和分配的内存,层次清晰,逻辑清晰。


首先,隔离列表的一层通过指向另一层的数组仔细管理不同大小的内存块。第二层对第一层进行线性划分,保证特定大小的内存能够快速定位。例如,当需要85Byte内存时,通过这样的设计,TLSF可以快速找到相应大小的FreeBlock,并且在实际场景中,可以轻松应对89Byte的需求。


每个BlockHeader字段不仅包含内存块的大小,还包含Prev_Phys_Block,以及专为FreeBlock设计的Next_free和Pre_free,以确保精确高效的内存管理。定位过程通过计算内存块大小和FirstLevel、SecondLevel的偏移量,兼顾效率和空间利用率。


总而言之,TLSF是SegregedFreeLists的创新改进。它巧妙地结合了线性除法的效率和指数除法的微量减少。FirstLevel采用指数除法来减少痕迹,而SecondLevel则引入线性除法来实现快速定位。这种组合使TLSF在处理小区间和大区间内存需求时能够保高效率并减少跟踪消耗,展现出理想的内存管理性能。


总体而言,TLSF以其独特的内存管理策略和数据结构设计,为实时系统提供了高效灵活的内存管理解决方案,是现代高性能应用必不可少的理想选择支持。