ptmalloc底层原理剖析

这篇具有很好参考价值的文章主要介绍了ptmalloc底层原理剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、概述

二、基础了解

2.1 32位进程默认内存布局

2.2 brk & sbrk & mmap

三、内存管理

2.1 结构

2.1.1 main_area 与 non_main_area

2.1.2 malloc_chunk

2.1.3 空闲链表bins

2.1.4 初始化

2.2 内存分配与释放

2.3 使用注意

三、ptmalloc、tcmalloc与jemalloc实现机制对比分析


一、概述

ptmalloc是开源 GNU C Library (glibc) 默认的内存管理器,当前大部分Linux服务端程序使用的是ptmalloc提供的malloc/free系列函数,而其在性能上远差于Meta的jemalloc和Google的tcmalloc

服务端程序调用ptmalloc提供的malloc/free函数申请和释放内存,ptmalloc提供对内存的集中管理,以尽可能达到:

  • 用户申请和释放内存更加高效,避免多线程申请内存并发和加锁

  • 寻求与操作系统交互过程中内存占用和malloc/free性能消耗的平衡点,降低内存碎片化,不频繁调用系统调用函数

为了内存分配函数malloc的高效性,ptmalloc会预先向操作系统申请一块内存供用户使用,并且ptmalloc会将已经使用的和空闲的内存管理起来;当用户需要释放内存free时,ptmalloc又会将回收的内存管理起来,根据实际情况决定是否回收给操作系统(内存池通性

二、基础了解

2.1 32位进程默认内存布局

ptmalloc底层原理剖析,C,c语言

栈至顶向下扩展,堆至底向上扩展,mmap映射区域至顶向下扩展。mmap映射区域和堆相对扩展,直至耗尽虚拟地址空间中的剩余区域

2.2 brk & sbrk & mmap

int brk(const void *addr)
void* sbrk(intptr_t incr)
  • 两者的作用都是扩展heap的上界
  • brk()的参数设置为新的brk上界地址,成功返回1,失败返回0
  • sbrk()的参数为申请内存的大小,返回heap新的上界brk的地址
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
int munmap(void& addr, size_t length)
  • mmap第一种用法是映射此盘文件到内存中
  • mmap第二种用法是匿名映射,不映射此盘文件,而向映射区申请一块内存,malloc使用的是第二种用法
  • munmap用于释放内存

三、内存管理

2.1 结构

为了解决多线程锁争夺问题,将内存分配区分为主分配区 (main_area) 和非主分配区 (no_main_area)。同时,为了便于管理内存,对预申请的内存采用边界标记法划分成很多块 (chunk);ptmalloc内存分配器中,malloc_chunk是基本组织单元,用于管理(描述)不同类型的chunk,功能和大小相近的chunk串联成链表,被称为一个bin

2.1.1 main_area 与 non_main_area

内存分配器中,为了解决多线程锁争夺问题,分为主分配区main_area(分配区的本质就是内存池,管理着chunk)和非主分配区no_main_area

  • ​ 主分配区和非主分配区形成一个环形链表进行管理

  • ​ 每个分配区利用互斥锁使线程对于该分配区的访问互斥

  • ​ 每个进程只有一个主分配区,允许有多个非主分配区

  • ​ ptmalloc根据系统对分配区的调用动态增加分配区的大小,分配区的数量一旦增加,则不会减少

  • ​ 主分配区可以使用brk()和mmap()来分配,而非主分配区只能使用mmap()来映射内存块

  • ​ 申请小内存时会产生很多内存碎片,ptmalloc在整理时也需对分配区做加锁操作

​当一个线程需要使用malloc分配内存时,先查看该线程的私有变量中是否存在一个分配区,若是存在,会尝试对其进行加锁操作。若加锁成功,就会在使用该分配区分配内存;若是失败,就会遍历循环链表中获取一个未加锁的分配区。若是整个链表中都没有未加锁的分配区,则会开辟一个新的分配区,将其加入全局的循环链表并加锁,然后使用该分配区进行分配。当释放这块内存时,同样会先获取待释放内存块所在的分配区的锁。若是有其他线程正在使用该分配区,则必须等待其他线程释放该分配区互斥锁后才能进行内存释放

注意:

  • 非主分配区虽然是mmap()分配,但是和大于128K直接使用mmap()分配没有任何关系。大于128K的内存使用mmap()分配,使用完之后直接用ummap()还给系统

  • 每个线程在malloc会先获取一个area,使用area内存池分配各自的内存,存在竞争关系

  • 为了避免竞争,可以使用线程局部存储的策略,thead cache(tcmalloc中的tc正是此意)

2.1.2 malloc_chunk

ptmalloc统一管理heap和mmap映射区域中空闲的chunk,当用户进行分配请求时,会先试图在空闲的chunk中查找和分割,从而避免频繁的系统调用,降低内存分配的开销。为了更好的管理和查找空闲chunk,在预分配的空间的前后添加了必要的控制信息

  • prev_size: 若前一个chunk是空闲的,该域表示前一个chunk的大小;若不空闲,该域无意义(知道当前chunk地址,减去prev_size,便得到前一个chunk的地址,prev_size主要用于相邻空闲的chunk合并)
  • size:当前chunk的大小,并且记录了如下一些其他属性
    • 前一个chunk在使用中 (P = 1)
    • 当前chunk是mmap映射区域分配 (M = 1) 或是heap区域分配 (M = 0)
    • 当前chunk属于非主分配区 (A = 0) 或非主分配区 (A = 1)
  • fd 和 bk: 只有该chunk空闲时才会存在,其作用是用于将对应的空闲chunk块加入到空闲chunk块链表中统一管理,若该chunk块被分配给应用程序使用,那么这两个指针也就没有用,所以此区域也被当作应用程序的使用空间
  • fd_nextsize & bk_nextsize:当前chunk存在于large bins中,large bins中的空闲chunk是按照大小排序,若存在多个同一大小的chunk,增加这两个字段可以加快遍历空闲chunk,并查找满足需要的空闲chunk,fd_nextsize指向下一个比当前chunk大的第一个空闲chunk,bk_nextsize指向前一个比当前chunk小的第一个空闲chunk。若该chunk块被分配给应用程序使用,那么这两个指针也就没有用,所以此区域也被当作应用程序的使用空间
//ptmalloc源码中定义结构体malloc_chunk来描述这些块
struct malloc_chunk
{
  INTERNAL_SIZE_T      prev_size;    /* Size of previous chunk (if free).  */  
  INTERNAL_SIZE_T      size;         /* Size in bytes, including overhead. */  
  
  struct malloc_chunk* fd;           /* double links -- used only if free. */  
  struct malloc_chunk* bk;  
  
  /* Only used for large blocks: pointer to next larger size.  */  
  struct malloc_chunk* fd_nextsize;      /* double links -- used only if free. */  
  struct malloc_chunk* bk_nextsize; 
};

使用中的chunk

ptmalloc底层原理剖析,C,c语言

  • chunk指针指向chunk开始的地址;mem指针指向用户内存块开始的地址
  • ​ P=0时,表示前一个chunk为空闲,prev_size才有效
  • ​ P=1时,表示前一个chunk正在被使用,prev_size无效。p主要用于内存块的合并操作。ptmalloc分配的第一个块总是将p设为1,以防程序引用到不存在的区域
  • ​ M=1为mmap映射区域分配;M=0为heap区域分配
  • ​ A=0为主分配区分配;A=1为非主分配区分配

空闲的chunk

ptmalloc底层原理剖析,C,c语言

 chunk空闲时,M状态不存在,只有AP状态。因为M表示是由brk还是mmap分配的内存,而mmap分配的内存free时直接munmap,不会放到空闲链表。原本是用户数据区的地方存储了四个指针。指针fd指向后一个空闲chunk,而bk指向前一个空闲的chunk,malloc通过这两个指针将大小相近的chunk连成一个双向链表

chunk中的空间复用

  • 为了使chunk占用的空间最小,ptmalloc采用了空间复用。一个chunk在不同状态下,某些区域表现出来不同的意义,以此达到复用
  • 空闲时,一个chunk至少需要 2个size_t和2个指针 大小的空间,用来存储prev_size、size、fd和bk,即16bytes
  • 当一个chunk处于使用状态时,其下一个chunk的prev_size域肯定是无效的,所以这个空间也可以被当前chunk使用

所以,一个使用中的chunk的大小的计算公式为:in_use_size = (用户请求 + 8 - 4)

加8bytes是为了存储prev_size和size,但又因为向下一个chunk借了4bytes,所以减去4。因为空闲的chunk和使用中的chunk使用的是同一块空间,所以要取最大值作为实际的分配空间,即最终的分配空间为chunk_size = max(in_use_size,16)

特殊chunk

top chunk

  • ​top chunk相当于分配区的顶部空闲内存,当bins都不能满足内存分配要求时,就会来top chunk上分配
  • ​当top chunk大小比用户所请求大小还大时,top chunk会分为两个部分,user chunk和remainder chunk(剩余大小)。其中remainder chunk成为新的top chunk
  • ​当top chunk大小小于用户所请求的大小时,top chunk就通过sbrk(main arena)或mmap(thread arena)系统调用来扩容

mmaped chunk

  • ​当分配的内存非常大(大于分配阈值,默认128k)时,需要被mmap映射,则会放到mmaped chunk上,当释放mmaped chunk上的内存时会直接交还给操作系统(chunk中M标志位为1)

last remainder chunk

  • ​last remainder chunk是一种特殊的chunk,就像top chunk和mmaped chunk一样,不会在任何bins中找到这种chunk,当需要分配一个small chunk,但在small bins中找不到合适的chunk。若last remainder chunk的大小大于所需要的small chunk大小,last remainder chunk被分裂成两个chunk,其中一个chunk返回给用户,另一个chunk变成新的last remainder chunk

2.1.3 空闲链表bins

当用户free内存,ptmalloc并不会马上将内存交还给操作系统,而是被ptmalloc的空闲链表bins管理起来,当下次进程需要malloc内存时,ptmalloc就会从空闲的bins上寻找一块合适的内存块分配给用户使用,避免频繁的系统调用,降低内存分配的开销

​ptmalloc将相似大小的chunk用双向链表连接起来,这样一个链表被称为一个bin,ptmalloc共维护了128个bin,每个bin都维护了大小相近的双向链表的chunk。基于chunk的大小,有下列几种可用bins:

ptmalloc底层原理剖析,C,c语言

 注意:32位平台下,bin[0]与bin[127]不存在。bin[1]为unsorted bins,bin[2]~bin[126]为sorted bins

unsorted bin

  • unsorted bins的队列位于bins数组的第2个(下标为1),是bins的一个缓冲区,加快分配的速度
  • 当用户释放的内存大于max_fast或者fast bins合并后的chunk都会首先进入unsorted bins,chunk大小无限制,任何大小chunk都可以进入。这种途径给予ptmalloc第二次机会重新使用最近free的chunk,寻找合适的bin的时间开销就省略了,因此分配和释放更快
  • ​用户malloc时,若fast bins没有找到合适的chunks,则malloc会先在unsorted bin中查找合适的空闲chunk。若没有合适的bin,ptmalloc会将unsorted bin上的chunk放入bins上,然后在bins上查找合适的空闲chunk

small bins

  • 小于512bytes的chunk被称为small chunk,而保存small chunk的bin被称为small bin。下标从2开始,到63结束,共62个。small bin每个bin之间相差8 bytes,同一个small bin的chunk具有相同大小
  • ​每个small bin都包括一个空闲区块的双向循环链表,free掉的chunk添加在链表的前端,而所需chunk则从链表后端摘除
  • ​两个相连的空闲chunk会被合并成一个空闲chunk,合并消除了碎片化的影响但是减慢了free的速度
  • ​分配时,当small bin非空,相应的bin会摘除binlist中最后一个chunk并返回用户。在free一个chunk时,检查其前或其后的chunk是否空闲,若是则合并,即将chunk从所属的链表中摘除合并成一个新的chunk,新的chunk会添加在unsorted bin链表前端

large bins

  • 大于512bytes的chunk被称为large chunk,而保存为large chunk的bin被称为large bin,位于small bins后面。下标从64开始,到126结束,共63个。large bins中的每个bin分别包含了一个给定范围内的chunk,其中的chunk按大小递减排序,大小相同则按照最近使用时间排列
  • ​两个相邻的空闲chunk会被合并成一个空闲chunk
  • ​分配时,遵循"smallest-first,best-fit",从顶部遍历到底部以找到一个大小最接近用户需求的chunk。一旦找到,相应chunk就会分成两块,user chunk(用户请求大小)返回给用户,remainder chunk剩余部分添加到unsorted bin
  • free和small bin类似

fast bins

程序在运行时会经常需要申请和释放一些较小的内存空间。当分配器合并了相邻的几个小的chunk后,也许马上就会有另一个小块内存的请求,分配器又需从大的空闲内存中切分出一块,较为低效,故引入fast bins

ptmalloc底层原理剖析,C,c语言

  • fast bins是bins的高速缓冲区,大约有10个定长队列(bin)。每个fast bin都记录着一条free chunk的单链表(binlist,采用单链表是因为fast bin中链表的chunk不会被摘除的特点),增删chunk都发生在链表的前端
  • ​当用户释放一块不大于max_fast(默认值为64bytes)的chunk时,会默认放到fast bins上。当需要给用户分配的chunk小于等于max_fast时,malloc首先会到fast bins上寻找是否有合适的chunk。一定大小内的chunk无论是分配还是释放,都会在fast bins中过一遍。
  • ​分配时,binlist中被检索的第一个chunk将被摘除并返回给用户,free掉的chunk将被添加在索引到的binlist前端

2.1.4 初始化

  • ​在堆区中,start_brk指向heap的开始,而brk指向heap顶部。可以使用brk() & sbrk()来增加分配给用户的heap空间。在使用malloc前,brk的值等于start_brk,即heap大小=0
  • ​ptmalloc在开始时,若请求的空间小于mmap分配阈值(默认为128KB)时,主分配区会调用sbrk()增加一块大小为(128KB + chunk_size)的空间作为heap,非主分配区会调用mmap映射一块大小为HEAP_MAX_SIZE(32位系统默认为1MB,64位系统默认为64MB)的空间作为sub-heap
  • ​当用户请求内存分配时,首先会在这个区域找一块合适的chunk给用户,当用户释放了heap中的chunk时,ptmalloc又会使用fast bins和bins来组织空闲chunk
  • ​若需要分配的chunk大小小于mmap分配阈值,而heap空间又不够,则此时主分配区会通过sbrk()调用来增加heap大小,非主分配区会调用mmap映射一块新的sub-heap,即增加top chunk的大小,每次heap增加的值都会对齐到4KB
  • 当用户的请求超过mmap分配阈值,并且主分配区使用sbrk()分配失败的时候,或是非主分配区在top chunk中不能分配到需要的内存时,ptmalloc会尝试使用mmap()直接映射一块内存到进程内存空间。使用mmap()直接映射的chunk在释放时直接结束映射,不再属于进程的内存空间。任何对该内存的访问都会产生段错误。而在heap中或是sub-heap中分配的空间则可能会留在进程内存空间内,还可再次引用

2.2 内存分配与释放

内存分配malloc流程

1、获取分配区的锁,防止多线程冲突(每个进程有一个malloc管理器,而一个进程中的多个线程共享这一个管理器,有竞争)

2、计算出需要分配的内存的chunk实际大小

3、若chunk 的大小 < max_fast(64bytes),在fast bins上查找适合的chunk;若不存在,转到 5

4、若chunk 大小 < 512bytes,从small bins上去查找chunk,若存在,分配结束

5、需要分配的是一块大的内存,或者 small bins 中找不到 chunk:

  • a. 遍历fast bins,合并相邻的chunk,并链接到unsorted bin中
  • b. 遍历unsorted bin中的chunk:
    • ①能够切割chunk直接分配,分配结束
    • ②根据chunk的空间大小将其放入small bins或是large bins中,遍历完成后,转到6

6、需要分配的是一块大的内存,或者small bins和unsorted bin中都找不到合适的 chunk,且fast bins和unsorted bin中所有的chunk已清除:

  • 从large bins中查找,遍历链表,直到找到第一个大小大于待分配的chunk进行切割,余下放入unsorted bin,分配结束

7、检索fast bins和 bins都没有找到合适的chunk,判断top chunk大小是否满足所需chunk的大小,从top chunk中分配

8、top chunk不能满足需求,需扩大 top chunk:

  • 当top chunk大小大于用户请求时,top chunk会分为两部分:User chunk和remainder chunk,其中remainder chunk成为新的top chunk
  • 当top chunk大小小于用户请求时,top chunk就通过sbrk()或者mmap()系统调用来扩容

9、top chunk也不能满足分配要求时,若是主分配区,调用sbrk()增加top chunk大小;若是非主分配区,调用mmap来分配一个新的sub-heap,增加top chunk大小;或者使用mmap()来直接分配:

  • 若所需分配的chunk大于等于mmap分配阈值,使用mmap系统调用为程序的内存空间映射一块chunk_size align 4KB大小的空间。然后将内存指针返回给用户
  • 若所需分配的chunk小于等于mmap分配阈值,判断是否为第一次调用malloc,若是主分配区,则需要进行一次初始化工作,分配一块大小为(chunk_size + 128KB) align 4KB 大小的空间作为初始的heap。若已经初始化过了,主分配区则调用sbrk()增加heap空间,非主分配区则在top chunk中切割出一个chunk,使之满足分配需求,并将内存指针返回给用户

内存释放 free 流程

1、获取分配区的锁

2、若free 的是空指针,返回

3、若当前chunk是mmap映射区域映射的内存,调用munmap () 释放内存

4、若chunk与top chunk相邻,直接与top chunk合并,转到 8

5、若chunk 的大小 > max_fast,放入unsorted bin,并且检查是否有合并:

  • a. 没有合并情况则free
  • b. 有合并情况并且和top chunk相邻,转到 8

6、若chunk 的大小 < max_fast,放入fast bin,并且检查是否有合并:

  • a.fast bin并没有改变chunk的状态,没有合并情况则free
  • b. 有合并情况,转到 7

7、在fast bins,若相邻chunk空闲,则将这两个chunk合并,放入unsorted bin。若合并后的大小 > 64KB,会触发进行fast bins的合并操作,fast bins中的chunk将被遍历合并,合并后的chunk会被放到unsorted bin中。合并后的chunk和top chunk相邻,则会合并到top chunk中,转到8

8、若top chunk的大小 > mmap收缩阈值(默认为 128KB),对于主分配区,会试图归还top chunk中的一部分给操作系统

2.3 使用注意

为了避免Glibc内存暴增,需要注意:

  1. 后分配的内存先释放,因为ptmalloc收缩内存是从top chunk开始,若与top chunk相邻的chunk不能释放,top chunk以下的chunk都无法释放
  2. ptmalloc不适合用于管理长生命周期的内存,特别是持续不定期分配和释放长生命周期的内存,这将导致ptmalloc内存暴增
  3. 多线程分阶段执行的程序不适合用ptmalloc,这种程序的内存更适合用内存池管理
  4. 尽量减少程序的线程数量和避免频繁分配、释放内存。频繁分配,会导致锁的竞争,最终导致非主分配区增加,内存碎片增高,且性能降低
  5. 防止内存泄露,ptmalloc对内存泄露是相当敏感的,根据其内存收缩机制,若与top chunk相邻的那个chunk没有回收,将导致top chunk一下很多的空闲内存都无法返回给操作系统
  6. 防止程序分配过多内存,或是由于Glibc内存暴增,导致系统内存耗尽,程序因OOM被系统杀掉。预估程序可以使用的最大物理内存大小,配置系统的/proc/sys/vm/overcommit_memory,/proc/sys/vm/overcommit_ratio,以及使用ulimt –v限制程序能使用虚拟内存空间大小,防止程序因OOM被杀掉

三、ptmalloc、tcmalloc与jemalloc实现机制对比分析

ptmalloc(glibc malloc):

  • ptmalloc是GNU C库(glibc)中的默认内存分配器,广泛用于Linux系统
  • 基于Doug Lea的malloc实现,采用了多种技术,如自由链表、分离器和堆的延迟绑定等
  • ptmalloc的特点是成熟、稳定,并且与GNU C库紧密集成

tcmalloc(Google malloc):

  • tcmalloc是Google开发的内存分配器,主要用于Google的C++代码
  • tcmalloc通过减少锁的竞争和减少内存碎片来提高性能
  • 使用线程本地缓存(Thread-Caching Malloc)的概念,将内存分配的任务分散到不同的线程中,以减少对共享数据结构的竞争
  • tcmalloc还有其他一些优化策略,如小对象合并、高效的分配器缓存等

jemalloc:

  • jemalloc是一款通用的内存分配器,由FreeBSD社区开发,并逐渐被其他系统广泛采用
  • jemalloc致力于提供高度可扩展性和低碎片化的内存分配
  • 使用了多个技术,如分离的内存区域、伙伴分配器、线程本地缓存等
  • jemalloc还提供了高级特性,如背景线程执行释放、空间利用统计和分析等

性能对比:

  • ptmalloc在大多数情况下性能良好,但在多线程环境下可能存在一些竞争问题
  • tcmalloc通过线程本地缓存和减少锁竞争,适用于高并发场景,尤其是多线程服务器应用
  • jemalloc在可扩展性和碎片化方面表现出色,特别适用于大型内存分配和高负载场景

总结:文章来源地址https://www.toymoban.com/news/detail-578781.html

  • ptmalloc适用于常规应用,与GNU C库集成紧密
  • tcmalloc适用于高并发多线程环境,通过线程本地缓存减少竞争
  • jemalloc适用于可扩展性和低碎片化要求高的场景,提供高级特性和统计信息

到了这里,关于ptmalloc底层原理剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 深入篇【C++】手搓模拟实现list类(详细剖析底层实现原理)&&模拟实现正反向迭代器【容器适配器模式】

    1.一个模板参数 在模拟实现list之前,我们要理解list中的迭代器是如何实现的。 在vector中迭代器可以看成一个指针,指向vector中的数据。它的解引用会访问到具体的数据本身,++会移动到下一个数据位置上去,这些都是因为vector具有天生的优势:空间上是连续的数组,这样指

    2024年02月15日
    浏览(46)
  • Linux源码解读系列是一套深入剖析Linux内核源码的教程,旨在帮助读者理解Linux操作系统的底层原理和工作机制

    Linux源码解读系列是一套深入剖析Linux内核源码的教程,旨在帮助读者理解Linux操作系统的底层原理和工作机制。该系列教程从Linux内核的各个模块入手,逐一分析其源码实现,并结合实际应用场景进行讲解。通过学习本系列,读者可以深入了解Linux操作系统的底层机制,掌握

    2024年01月21日
    浏览(50)
  • 【C语言】剖析qsort函数的实现原理

    主页:17_Kevin-CSDN博客 专栏:《C语言》 本文将从回调函数,qsort函数的应用,qsort函数的实现原理三个方面进行讲解,请自行跳转至相对位置进行阅读~  目录 回调函数 qsort函数的应用 qsort函数实现原理 回调函数实际上是一个指针,指向的是一个函数。它作为一个参数传递给

    2024年03月14日
    浏览(35)
  • 6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理

    1、Go版本 2、汇编基础 推荐阅读:GO汇编语言简介 推荐阅读:A Quick Guide to Go\\\'s Assembler - The Go Programming Language 精简指令集 数据传输: MOV/LEA 跳转指令: CMP/TEST/JMP/JCC 栈指令: PUSH/POP 函数调用指令: CALL/RET 算术指令: ADD/SUB/MUL/DIV 逻辑指令: AND/OR/XOR/NOT 移位指令: SHL/SHR JCC有条件跳转: JE

    2024年02月04日
    浏览(41)
  • 哈希表(底层结构剖析--下)

    由于哈希桶的本质就是一个存有结点指针的数组.所以哈希桶存储的数据类型便是结点指针类型. 哈希结点中包括两个内置成员: 1:K,V模型组成键值对pairK,V.(也可以是K模型) 2: 指向下一个结点的指针. 哈希桶的本质是一个指针数组. 其内置成员有两个: 1: 装有结点指针的vector. 2: 记

    2024年02月01日
    浏览(32)
  • 哈希表(底层结构剖析-- 上)

    1: 在顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系.因此,在查找一个元素时,必须要经过关键码的多次比较.我们知道顺序表查找的时间复杂度为0(N),平衡树中的查找的时间复杂度则为树的高度,即O(log2N),此时,搜索的效率取决于搜索过程中元素的比较次数

    2024年02月01日
    浏览(29)
  • Go语言网络编程:HTTP服务端之底层原理与源码分析——http.HandleFunc()、http.ListenAndServe()

    在 Golang只需要几行代码便能启动一个 http 服务,在上述代码中,完成了两件事: 调用 http.HandleFunc 方法,注册了对应于请求路径 /ping 的 handler 函数 调用 http.ListenAndServe,启动了一个端口为 8999 的 http 服务 2.1 server 结构 Addr :表示服务器监听的地址。如\\\":8080\\\"表示服务器在本地

    2024年02月08日
    浏览(65)
  • Spring Boot 常见的底层注解剖析

    Spring Boot 是一个用于创建独立的、基于Spring框架的Java应用程序的框架。它提供了许多注解,用于配置和定制应用程序的行为。以下是一些常见的Spring Boot底层注解的剖析: @SpringBootApplication :这是一个组合注解,用于标记一个主要的Spring Boot应用程序类。它包括 @Configuration 、

    2024年02月14日
    浏览(41)
  • 【C++干货铺】剖析string | 底层实现

    ========================================================================= 个人主页点击直达: 小白不是程序媛 C++专栏: C++干货铺 代码仓库: Gitee ========================================================================= 目录 成员变量 成员函数 构造和拷贝构造 赋值重载 析构函数 operator[ ] size 迭代器  rese

    2024年02月05日
    浏览(41)
  • openmv底层算法剖析---梦飞openmv前传

    前言 接梦飞openmv博客,本篇重点剖析openmv的算法和功能实现。openmv是国外开源团队依托mirco-python架构开发的一套基于stm32内核优化算法的图像识别模组,其目的是让图像视觉算法应用开发更加简便,算法运行效率更高,其底层代码全部由C语言实现,上层代码用micro-python开发。

    2024年02月13日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包