前端时间笔者系统学习了基础组件中的池式结构(包括线程池、内存池、连接池),原子操作,锁,无锁队列,网络缓冲区,定时器设计,分布式锁,有些内容笔者已经总结整理成了相关技术文档,读者若感兴趣可以翻看笔者的个人空间进行查阅,剩余没写的笔者会在近期总结整理。
本文是笔者在阶段性学习后进行的一次全面总结整理,旨在对之前没整理到的技术细节以及面试常问的问题表述进行查漏补缺,并且分享给大家。
一、线程池
问:聊一聊线程池(这种问题问的很泛,要先回答重点,像这种很泛的问题如果都能描述的到位,说明掌握的不错)
围绕三个方面展开:线程池是什么?解决了什么问题?运行原理是什么?
线程池是一个维护着固定数量线程的池式结构,池式结构的主要作用是复用资源。
线程池解决了什么问题:1、用户线程可以将耗时任务交给线程池中的线程进行处理,避免了用户核心线程的阻塞;2、避免了线程的频繁创建和销毁,从而影响系统性能。
线程池的运行原理:大部分我前面文章都说了,这里补充一个需要优先表述的重点:用户线程和线程池对应一个生产者-消费者模型,因此需要一个任务队列,生产者线程(用户线程)往里push任务,消费者线程(线程池中线程)从里pop任务来消费,当队列为空时阻塞消费者线程,解放cpu。
可能的追问:线程池中线程的数量如何确定?
回答可参见之前的线程池文章,如果没追问可以自己视情况决定是否自己额外补充。
二、内存池
问:聊一聊内存池
继续围绕这三方面展开:内存池是什么?解决了什么问题?运行原理是什么?
内存池是一个维护着预分配内存块的池式结构,池式结构的主要作用是复用资源。
内存池解决了什么问题:1、避免了用户频繁的申请和释放内存操作,提高系统性能;2、集中管理内存块,避免了内存泄漏和内存碎片的问题。
内存池的运行原理:前面的文章已有介绍,回答时可以主要讲内存池的数据类型、构成等。
可能的追问1:内存碎片是什么?如何产生?(这里可以细讲内部碎片和外部碎片,下面只讲了外部碎片)
内存碎片是指在内存管理过程中,随着内存分配和释放,系统中出现的无法利用的空闲内存区域。碎片可能会影响程序的性能和内存使用效率,甚至导致系统崩溃。
内存碎片产生的原因是当系统进行动态内存分配(如 malloc
或 new
)时,操作系统会在空闲内存区域中找到一个合适的空闲块并分配,这可能导致分配的内存块之间存在很小的未分配的内存块,但其大小不满足后续的内存申请。
可能的追问2:讲一下malloc的实现细节
malloc是一个库函数,通过操作系统的底层系统调用来向程序分配内存。malloc自己本身也维护着一个内存池,malloc函数本身是暴露给用户使用的接口。当malloc分配的内存<128k时,通过brk系统调用从堆区分配内存(优先从malloc内存池中分配以减少系统调用,free后还给内存池,可复用);当>128k时,通过mmap系统调用从文件映射区分配内存(每次都会系统调用,free后归还操作系统)。
malloc分配的是虚拟内存,若分配的内存没有被访问,则不会映射到物理内存,即不访问就不占用物理内存,访问则通过缺页异常机制从磁盘加载缺失的页面,从而建立虚拟内存和物理内存的映射关系。
可能的追问3:malloc自身已经维护一个内存池,为什么还要在用户态自己设计一个内存池?
因为malloc的内存池是通用的设计,并不一定满足用户在某个业务场景下的最优需求,因此可以针对性优化。
三、连接池
问:聊一聊连接池
同样分三点阐述:连接池是什么?连接池解决了什么问题?连接池的运行原理?
连接池一般都是指数据库连接池,可以以MySQL举例,即连接池是一个维护着一定数量的MySQL连接的池式结构,池式结构的主要作用是复用资源。
连接池解决了什么问题:1、避免了频繁建立和断开连接所需要的耗时操作(tcp三次握手建立连接,MySQL认证、sql执行、tcp四次挥手断开连接);2、统一的连接管理,避免数据库连接泄露。
运行原理:具体可参见连接池的文章,这里补充一步表述:同步连接池是一个链接绑定一把锁,异步连接池是一个连接绑定一个线程。
先写到这儿,未完待续……