内存池的面试整理

面试问题之高并发内存池项目 高并发内存池的问答 阅读详情

文章思路来源

注意:不是面试官问的问题,我只是按照问答的形式进行整理

  • 如何实现无锁申请?
    • 每个线程申请自己的TreadCacheTLS对象,来管理自己的freeList数组。
  • 小内存的大小?
    • 0-256K,并且对申请到的内存进行字节对齐,保证申请到的内存可以映射到对应的freeList中。
    • 映射规则?
      • 从128字节开始每个区间8倍递增,从16(8到16是两倍)字节开始对齐每8倍递增,到256KB,8K对齐结束。每个区间为16,56,56,56,24,共208个freeList
    • 为什么从8字节开始对齐?让freeList保存下一个节点的地址,即使在64位系统下
  • freeList如何管理内存?
    • 将申请到的内存块头插到对应的freeList,每次需要内存就头删一个内存块。

  • 如何向centralCache申请内存?
    • 首先利用相同的哈希值(两个cache都包含相同数量的哈希桶)来得到对应的spanList,获取到一个span,里面存储的是切好size大小的freeList,并且物理空间是连续的。然后返回ThreadCache需要的内存块数。

  • 如何连续?
    • 将申请到的未切分span,进行尾插
  • 如何向pageCache申请内存?
    • 首先将centralCache申请的页数(不足一页申请一页),映射到对应的spanList上,取出一个span,并记录span内每个页号和span的映射关系后,返回给centralCache。
    • 为空则向spanList后遍历,如果找到一个span,则再创建一个span,一个span存所需的页,返回给centralCache,一个span存剩余的页,并将这个span挂到对应spanList内。
    • 都为空,则向系统申请一个128页的大span,重新进行前面的流程。创建两个span,一个span返回,一个span挂到对应spanList内。
  • central cache和pagecache都是单例模式
  • pageCache映射规则:页号根据得到的地址/页大小
  • 为什么双向链表?
    • 方便回收span时,找到前一个节点
  • 项目中有使用new吗
    • 新建了一个定长内存池,每次需要对象时从这里面申请,并且用的是定位new,直接再给定地址内开辟空间
  • 内存池只分配内存给对象,至于内存如何使用就看对象如何使用比如将void*转换为int*然后修改指向的空间
  • 什么时候加锁?
    • centralCache从span中返回内存块时加锁(删除)
    • centralCache将pageCache中的span挂到spanList时加锁(增加)
    • centralCache合并内存块到span需要加锁(合并)
    • PageCache寻找可用span时需要加锁(删除)
    • PageCache合并span时需要加锁(合并)
    • 一般涉及到对数据的增删改操作时,需要加锁
  • 如何释放内存?
    • ThreadCache释放指向内存空间的指针时,会根据指针地址找到页号然后找到对应的span,根据span内的信息(进而知道内存块大小),就能找到归还的freeList,当归还的内存块等于最初的未分配(批量申请的)内存块数量后,就可以归还这个span给spanlist。
    • 将调用centralCache函数,找到该freeList的所属的spanList,加锁后,根据页号和span的关系,将freeList归还给spanList内的span,解锁后
    • 调用PageCache函数,PageCache同样利用页号和span的关系进行向前向后合并,将合并后的span挂到对应spanList内,并在spanList内删掉合并用掉的span
    • 页号和地址的可以互相转换,只需要将地址除8K得到页号,因为每个地址都是以8K递增,相应的页号+1
    • 向前向后合并的条件是,span不为空且没有被使用
  • 大内存如何申请?
    • 计算对齐后需要的页数,然后PageCache向系统申请空间,建立页号和span的映射后返回该span,利用span的页号左移13位得到指针地址并返回。释放该内存,则直接释放给系统,而不是还给内存池。
  • 链表的头节点,如何连接?
    • 头几个字节,并且为了适配不同平台,将一级指针强转为二级指针再取其地址。
  • 改进的点?
    • 使用RAII机制管理锁
    • 加入日志线程
  • freeList,spanList
    • freeList记录申请内存块数,批量申请的数量
    • spanList记录span的头节点
    • span记录页号、页数、前后指针、切好的size大小、使用掉的内存块数、是否在使用
  • 慢开始机制
    • 申请块数以1递增,直到当前申请的内存块数大于最大可申请数
  • 亮点/细节:
    • 慢开始机制
    • 基数树
    • 为了保证连续,进行尾插
    • 使用定长内存池模板,每次创建list的头节点都从里面申请

  • ConcurrentAlloc:首先,当线程需要size个字节时,会从定长内存池中先加锁创建tls线程缓存对象,
  • Allocate:将size进行字节对齐,并计算key找到对应的freeList,从该freeList中无锁的获取头部的内存块(哈希桶用每个定长内存块的头部来作为链表下一个节点的地址)
    (哈希桶的映射规则是
    0-128,以8字节对齐,分为0-15,
    129-1K,以16字节对齐,分为16-71,
    1K+1-8K,以128字节对齐,分为72-127,
    8K+1-64K,以1024字节对齐,分为128-183,
    64K+1-256K,以8K对齐,分为184-207)
  • FetchFromCentralCache:如果对应freeList为空,则向中间缓存利用慢开始机制申请一定数量的内存块,
  • FetchRangeObj:首先中间缓存根据相同的key来找对应的spanList,内部存储切好size大小的freeList(每个span(大小为8K)内包含一定数量的size内存块,)然后加锁从桶内的一个span获取(头删)需要的内存块数,线程缓存得到中间缓存分配的内存块后,将第一个内存块分给线程,将剩余的内存块头插到freeList里。
  • GetOneSpan:如果中间缓存的当前span哈希桶为空,首先把中间缓存锁解锁用以防止其他线程释放内存时需要等待,然后加上页锁,向页缓存申请空间,
  • NewSpan:页缓存保存的是管理页的spanList,它的映射规则是直接定址法,每个key保存的都是key个页的span。
    • 中间缓存需要申请k个页时映射到对应spanList上,取出一个span,建立页号和span的映射,返回给中间缓存,
    • 如果对应spanList没有span,就遍历k之后的spanList,有则切分k个,并将剩余的span头插到对应的spanList上,建立页号和span的映射,返回这个span。
    • 如果k之后的spanList都为空,则从定长内存池新建一个span对象,为其分配128页连续的内存空间,然后重新切分k,头插剩余的span到对应spanList内+映射,返回这个span。
  • GetOneSpan:中间缓存拿到span后解锁页缓存锁,将span划分为size大小的内存块,保持物理空间连续,将切好的span加锁后头插到对应spanList内,从span内获取n个对象返回给线程缓存,线程缓存在返回一个对象给线程,并把剩下的对象头插到对应freeList内。

释放内存:

MapObjectToSpan:计算指针地址到span的映射,获取内存块的大小
Deallocate:根据内存块的大小归还到相应freeList内,当其内的内存块数量大于分配的数量后,
分配的数量有慢开始机制计算,每次申请就递加一个,(机制)
ListTooLong:就把这些归还给centralCache
ReleaseListToSpans:根据相同的key找到spanList后,加锁后,根据映射关系将内存块归还给span里的freeList,直到所有内存块归还完毕后就将这个span归还给pageCache,解锁
ReleaseSpanToPageCache:加锁,首先看

  • 向前能否合并,根据前一个span的页号找到前一个span判断是否为空,是否正在被使用,是则无法合并
    • 然后向前合并页号以及页数,并把前一个span对应的spanList删除,并且回收前一个span的空间
    • 循环上述判断直到退出
  • 向后能否合并,根据后一个span的页号(span+页数=后一个)找到对应span,进行向后合并,直到不满足后一个span不为空,未使用。
  • 将合并后的span挂到指定位置,并建立页号和span的映射关系(重复则覆盖)
  • 解锁

总体过程:

首先当线程申请内存时,创建一个线程局部存储对象,进行字节对齐后,映射到线程缓存的freelist对应位置,从中头删一个内存块返回给线程。如果没有,则根据同样的映射值获取中间缓存对应的spanlist内的span,并头删一定数量的内存块返回。如果不存在满足的span,向页缓存根据申请的页数映射到对应的spanlist中返回一个span。如果不存在则向系统申请一个128页的span,从中分割成两部分,一部分满足页数返回给中间缓存,一部分存储到对应的哈希桶内。然后再一级级的返回给线程(中间缓存分割span后,将内存块返回给线程缓存,最后再将内存块返回给线程。)

ThreadCache释放指向内存空间的指针时,会根据指针地址找到页号然后找到对应的span,根据span内的信息,就能找到归还的freeList,当归还的内存块等于最初的未分配内存块数量后,就可以归还这个span给spanlist,然后遍历span前后,当其不使用且不为空则进行合并。

整理收集python面试常见题目 python面经 阅读详情

相关推荐

UE4 面试题整理

new首先会去调用operator new函数,申请足够的内存(大多数底层用malloc实现),然后调用类型的构造函数来初始化变量,最后返回自定义类型的指针,delete先调用析构函数,然后调用operator delete函数释放内存(大多数底层用free实现)不可以,在DS(dedicated server)模型下,AIController只存在于服务端,其主要是通过在服务端对Pawn进行操控,sprintf:sprintf函数用于将格式化的字符串输出到一个字符数组中。然后再同步到客户端。

qqQQqsadfj的博客 1万+

内存池管理项目——面试题总结

伙伴系统算法实现:定义WORD b结构体⽤于表⽰内存块,含前驱指针llink、标识tag、块⼤⼩幂次kval和后继指针rlink;MyFree函数判断释放块与伙伴块状态,合并空闲伙伴块后将其插⼊相应可利⽤空间链表;Show函数输出占⽤块信息,ShowPav函数输出 可利⽤空间表中所有空闲块信息。通过InitMem函数初始化内存池, 在内存池前后添加 “墙” 防⽌越界;项⽬概述:本项⽬通过实现⾸次拟合法和伙伴系统算法,完成对内存池的管理,旨在为程序提供⾼效、合理的内存分配与回收机制,优化内存使⽤效 率。

hxd030228的博客 959

开关电源PCB安规设计避坑指南:从光耦开槽到变压器挡墙,这些细节决定认证成败

本文深入解析开关电源PCB安规设计中的关键细节,包括光耦开槽、变压器挡墙工艺等12个致命要点。通过实际案例和工艺参数表,揭示如何避免认证失败,特别强调爬电距离和电气间隙的精确控制,助力工程师提升产品安全性和认证通过率。

weixin_42548893的博客 202

C++面试:内存篇

c++内存方面总结

葛雨龙的博客 623

树莓派5安装ROS2小白指南避坑攻略

手把手教你如何在树莓派5上顺利安装ROS2,避开常见问题与陷阱,提升配置效率。针对树莓派5安装ros2过程中的依赖冲突、源配置错误等高频难题提供解决方案,适合新手快速上手。

weixin_35754962的博客 1003

【Unity】ABB CRB 15000 外部引导运动实战:从配置到实时控制

本文详细介绍了ABB CRB 15000协作机器人的外部引导运动(EGM)功能在Unity环境中的实战应用。从RobotStudio配置到Unity实时通信架构,再到EGM运动控制技巧和问题排查,全面解析如何实现机器人的高精度实时控制。通过实际案例展示EGM技术在精密装配等场景中的显著效果,帮助开发者快速掌握这一先进技术。

weixin_29057695的博客 444

(面试经典问题之内存池篇)内存池构成、作用及其基本原理详解

内存池是一种管理和复用内存的技术,通过预分配一定量的内存块并对其进行维护,从而避免频繁的内存申请和释放,提升系统性能,尤其在高并发的应用场景下尤为重要。内存池通过减少内存操作的开销,优化程序的内存管理,避免频繁的内存分配与释放导致的性能瓶颈。内存池是提升系统性能的关键技术之一,特别是在高并发、内存密集型的应用场景中,内存池通过预分配固定大小的内存块,避免了频繁的内存申请和释放操作,从而减少了内存碎片、提升了效率。

hz_uzi的博客 555

英飞凌AURIX 2G 系列MCU关于外设模块EVADC的实现原理及对应MCAL(EB Tresos)配置项详细讲解

本文章讲述了英飞凌AURIX 2G系列MCU关于外设模块EVADC的实现原理及对应MCAL配置工具(EB)的配置项。

weixin_46176506的博客 6274

【23秋招c++后端面试技术突围】 分析高效内存池的实现方式

群内提供免费的C/C++Linux服务器开发/高级架构师学习资料资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,,只有当内存池不够大需要动态扩增的时候才会调用系统的分配内存函数,其他时间对内存的一切操作都是用应用程序控制的。(在这里的固定指的是每一次和系统申请的内存的大小都是固定的,而不是这个内存池大小只能那么大)和。后面随着内存池的不断扩大,我们通过。

m0_58687318的博客 677

LSTM预测股票数据---数据预处理

# 导入相应的模块 import pandas as pd import numpy as np import matplotlib.pyplot as plt import tensorflow as tf # 获取训练集 def get_train_data(data,batch_size = 60 ,time_step = 20,train_begin = 0,train_end = 58...

qq_35358021的博客 3359

PD虚拟机网络初始化失败的权限修复指南

本文针对Parallels Desktop虚拟机常见的“网络初始化失败”问题,提供了详细的权限修复指南。通过分析问题根源,指导用户安全备份并修改关键的`network.desktop.xml`和`dispatcher.desktop.xml`配置文件,以恢复PD虚拟机的网络连接。文章还包含了修复后的验证步骤及预防措施,帮助用户彻底解决并避免此类权限问题。

qqq44的博客 849

碎片整理设计Back-End-Developer-Interview-Questions:存储优化算法

在现代后端开发中,存储性能往往是系统瓶颈的关键所在。随着数据量的指数级增长,传统的存储管理方式已经无法满足高性能应用的需求。碎片化(Fragmentation)问题会导致存储空间利用率低下、I/O性能下降,甚至影响整个系统的稳定性。 > "一个优秀的后端开发者不仅要会写代码,更要懂得如何优化存储,这是区分普通程序员和架构师的重要分水岭。" 本文将深入探讨碎片整理的核心算法,结合Back-End...

gitblog_00362的博客 708

CAN轴控制流【6041,6040】

【代码】CAN轴控制流【6041,6040】

cfqq1989的博客 1782

鸿蒙内核源码分析 (内存池管理) | 如何高效切割合并内存块

动态分配系列篇将动态分配分成上下两篇,本篇为下篇,阅读之前建议翻看上篇。鸿蒙内核源码分析(TLFS算法) 结合图表从理论视角说清楚 TLFS 算法鸿蒙内核源码分析(内存池管理) 结合源码说清楚鸿蒙内核动态内存池实现过程,个人认为这部分代码很精彩,简洁高效,尤其对空闲节点和已使用节点的实现令人称奇。为了便于理解源码,站长画了...

weixin_28800247的博客 335

C# 与华中数控设备通信:数控机床自动化控制与实时监测系统

华中数控系统与C#通信开发指南 核心要点 通信基础 支持串口(RS232/RS485)和以太网两种连接方式 协议选择:通用Modbus协议或华中自定义HNC协议 关键数据映射表明确各参数对应的寄存器地址和功能码 系统架构 四层架构:设备层→通信层→业务层→应用层 包含实时数据采集、指令下发、状态监控、异常处理全流程 支持Modbus和HNC协议动态切换 代码实现 串口通信使用NModbus库简化开发 提供连接管理、数据读取、指令下发完整示例 包含异常处理和超时重连机制 应用价值 实现数控机床远程监控和自动化

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 2015

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

从基础到进阶、底层的188道iOS面试题,下篇(87-188)!

'写给读者的话????' 这些是我对iOS面试时会碰到的问题的解决方法,梳理和整合百度、阿里等100家企业面试题,想要更加详细的查看题目的回答,已链接出比较完全的答案,出来分享给大家,题目下的回答有点错误那也是正常的了,希望对大家有所帮助。大家有更好的解决办法也欢迎沟通交流。对于技术不足之处,还望谅解和大佬的指导!!???? 最后欢迎加入我的iOS交流圈资料获取: +裙:196800191 或者是+ W...

zengfengfengfeng的博客 212

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

python查询和替换一个文本字符串_【Python】python面试题

一些Python面试题1. (1)python下多线程的限制以及多进程中传递参数的方式python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不是“并行”。多进程间共享数据,可以使用 multiprocessing.Value 和 multiprocessin...

weixin_39712611的博客 577

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

大数据python试卷_python面试题大全(一)

python面试题大全(一)最近开始整理python的资料,博主建立了一个qq群,希望给大家提供一个交流的同平台 938587844 。1. (1)python下多线程的限制以及多进程中传递参数的方式python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一个线程使用解释器,跟单cpu跑多个程序一个意思,大家都是轮着用的,这叫“并发”,不...

weixin_39699670的博客 427

C++面经汇总

C++常见面经

weixin_45029883的博客 378

内存池项目(4)——总结

答案:内存池是一种内存管理技术,它在程序运行开始时预先分配一块较大的内存空间作为池,当程序需要分配小块内存时,直接从这个池中获取,而不是每次都向操作系统申请。当使用完这些小块内存后,也不是立即归还给操作系统,而是将其放回内存池,以便后续再次使用。这样可以减少内存分配和释放的系统开销,提高内存分配效率,同时也有助于减少内存碎片。

hxd030228的博客 740

“深入浅出”系列之Linux篇:(14)内存池

答案定义:内存池是一种内存管理技术,它预先分配一大块连续的内存区域,之后在程序运行过程中,当需要内存时,直接从这个预先分配好的内存块中获取,而不是每次都向操作系统请求内存;当释放内存时,也不是立即将内存归还给操作系统,而是将其标记为可重用状态,供后续的内存分配使用。原因:减少内存碎片:频繁的内存分配和释放会导致内存碎片问题,使得可用内存空间变得零散,无法满足大块内存的分配需求。内存池通过预先分配和管理内存,减少了这种碎片的产生。提高性能:向操作系统请求内存(如使用malloc或new。

weixin_65589140的博客 761

熬夜整理的 Java 面试题

金九银十来临,前几天朋友出去面试……回来抱怨说面试时各种分布式、高并发、底层源码连环套一样打过来,幸亏基础够扎实,不然扛不住。现在还感叹金九银十果然不是吹的,面试难度都比其他月份要高。正值...

公众号:逛逛GitHub 237

最强面试题整理第二弹:Python 进阶面试题(附答案)

大家好呀,我是 Rocky0429。 Python 面试的时候,会涉及到很多的八股文,我结合自己的经验,整理Python 最强面试题。 Python 最强面试题主要包括以下几方面: Python 基础(已完成) Python 进阶(已完成) Python 后台开发 爬虫 机器学习 对每道面试题会附带详细的答案,无论是准备面试还是自己学习,这份面试题绝对值得你去看,去学习。 1、Python 中类方法、类实例方法、静态方法有何区别? 类方法:是类对象的方法,在定义时需要在上方使用“@classmetho

Rocky0429 7806

面试问题整理第二天

今日分的面试整理出来了。今天先写心情。 跑了颐和园附近和丰台紫金园附近,车上大概花了4个小时的时间吧。结果上午面试了40分钟,下午聊了30分钟。也没有做题,就是招聘经理过来直接跟你聊,聊项目,聊技术。不过下午这家虽然是小公司,但是感觉挺实在的,我有点赌徒的心态,想要去和他们一起发展。虽然最后的结果可能是这家公司黄了,发不出工资什么的,有一些其他坑什么的。但是只要公司不是这样,那对于我来说就是赌赢了...

lwylhh的博客 183

Netty面试题分类整理

Netty面试要点精要: Netty是一个高性能异步网络框架,采用主从Reactor线程模型(Boss/Worker Group)实现高并发。核心组件包括Channel、EventLoop、Pipeline和ByteBuf等,形成责任链式处理流程。其优势在于:1)异步非阻塞设计,少量线程处理大量连接;2)内存池和零拷贝技术提升性能;3)灵活的Pipeline处理机制;4)提供多种解决TCP粘包问题的解码器。优化建议包括合理配置线程数、使用内存池、Epoll多路复用等。

weixin_39956506的博客 744

整理100道Python面试真题,拿下月薪过万offer无压力!丈母娘都刮目相看

大家好,我是老牛。 最近很多人都在技术学习群找我咨询面试找工作的问题,这次我就专门打包整理了100道Python面试真题,希望能对大家有帮助。 1、Python基础 1.说一说你所知道的 Python 数据结构有哪些。 2.Python 中列表和元组的区别是什么?元组是不是真的不可变? 3.什么是生成器和迭代器?它们之间有什么区别? 4.什么是闭包?装饰器又是什么?装饰器有什么作用?你用过装饰器吗?请写一个装饰器的例子。 5.说一下什么是匿名函数,用匿名函数有什么好处? .

zz116196的博客 1884
上一篇: 混合编程python与C++
AlexNett
博客等级 码龄9年 562粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值