最新要闻
- 乌尔善揭秘《封神第一部》拍摄:最大摄影棚 马跑8秒就出景
- 新疆“海鲜”上新:沙漠里的澳洲龙虾丰收啦!一斤130元
- 中国成世界最大投影市场:“中国制造”全球占比超75%
- 纯燃油车垂死挣扎 今年新车数量占比快跌到1/4了
- 全铝车身+后置后驱:奇瑞全新suv即将上市 命名“舒享家”
- 巴奴火锅称羊肉卷确实含有鸭肉成份:向顾客赔偿835.4万元!
- 机皇预定!曝华为Mate 60 Pro+明天开售:标配16GB内存 512GB起步
- “特斯拉强敌”就要来了!Lucid加快进度 计划进入中国市场
- 华为Vision智慧屏SE3正式开售:2499元起 双120Hz高刷
- 1199元 小米AR体感运动主机上架:12核双芯+超广角镜头
- 唯一的双风扇!七彩虹iGame RTX 4070 Ultra限时降价100元
- 立减70元 29.9元到手!班尼路大牌长袖卫衣大促
- 土耳其玩家暴怒!PS+订阅费用在土区暴涨近5倍
- 浙江一村庄出现上千条眼镜蛇 竟是偷偷放生:当地回应
- 如何从周四就开始过周末?
- 驾驶特斯拉撞车:林志颖称车祸后理解能力变差 脸部留疤
手机
又是一年开学季丨无缝接驳 直通高校 武汉贴心迎新
科锐国际廖萍: 数字化人才将成为VUCA时代企业人才战略的核心
- 又是一年开学季丨无缝接驳 直通高校 武汉贴心迎新
- 科锐国际廖萍: 数字化人才将成为VUCA时代企业人才战略的核心
- 郑州地铁3号线二期通过初期运营前安全评估
- 筑牢基层安全“防火墙”盘龙区金辰街道这么做
- 中金关注政策组合拳的长期积极影响
- 军士选晋,为战选才!
家电
126.STL 之 空间配置器(allocator)
126.STL 之 空间配置器(allocator)
1.SGI 标准的空间配置器,std::allocator
SGI也定义了一个符合部分标准,名为allocator的配置器,但是它自己不使用,也不建议我们使用,主要原因是效率不佳。
它只是把C++的操作符::operator new和::operator delete做了一层简单的封装而已。
【资料图】
2.SGI 特殊的空间配置器,std::alloc
由于SGI 标准的空间配置器只是把C++的操作符::operator new和::operator delete做了一层简单的封装,没有考虑到任何效率上的强化。
所以 SGI 出现了一个特殊的空间配置器,供 STL标准模板库使用。
通常,C++中用new操作符来分配内存都包括两个阶段:
(1)调用::operator new配置内存
(2)调用构造函数来构造对象内容
同理,delete操作也包括两个阶段:
(1)调用析构函数将对象析构
(2)调用::operator delete释放内存
为了精密分工,SGI STL allocator将两个阶段分开:
内存配置操作由alloc:allocate负责,内存释放由alloc:deallocate负责;对象构造操作由::contructor()负责,对象析构由::destroy()负责。
配置器定义在头文件
#include // 负责内存空间的配置和器释放 #include // 负责对象的构造和析构
3.STL 空间配置器:
3.1STL 空间配置器解决的问题
1.内存碎片问题(外碎片)
内碎片:操作系统在分配给申请者未被利用的部分。产生原因:内存对齐(效率高);
外碎片:内存充足时但分配不出大块内存。产生原因:由于多次分配小块内存,将大块内存分割成小块;
2.频繁系统分配,释放小块内存,调用 malloc,delete 系统调用产生性能问题;
STL 空间配置器的实现机制:
3.2双层级的配置器
注:
当需要开辟的空间大于 128 bytes 时,视为“足够大”,调用一级配置器,直接调用 malloc,free;
当需要开辟的空间小于 128 bytes 时,视为“过小”,为了降低额外负担,调用二级空间配置器
A.一级空间配置器
//以下是第第一级配置器template class __malloc_alloc_template {private: //以下函数用来处理内存不足的情况 static void* oom_malloc(size_t); static void* oom_realloc(void*, size_t); static void (*__malloc_alloc_oom_handler)();public: static void* allocate(size_t n) { void* result = malloc(n); //第一级配置器,直接使用malloc() //如果内存不足,则调用内存不足处理函数oom_alloc()来申请内存 if (0 == result) result = oom_malloc(n); return result; } static void deallocate(void* p, size_t /* n */) { free(p); //第一级配置器直接使用 free() } static void* reallocate(void* p, size_t /* old_sz */, size_t new_sz) { void* result = realloc(p, new_sz); //第一级配置器直接使用realloc() //当内存不足时,则调用内存不足处理函数oom_realloc()来申请内存 if (0 == result) result = oom_realloc(p, new_sz); return result; } //设置自定义的out-of-memory handle就像set_new_handle()函数 static void (*set_malloc_handler(void (*f)()))() { void (*old)() = __malloc_alloc_oom_handler; __malloc_alloc_oom_handler = f; return(old); }};template void (*__malloc_alloc_template::__malloc_alloc_oom_handler)() = 0; //内存处理函数指针为空,等待客户端赋值template void* __malloc_alloc_template::oom_malloc(size_t n){ void (*my_malloc_handler)(); void* result; for (;;) { //死循环 my_malloc_handler = __malloc_alloc_oom_handler; //设定自己的oom(out of memory)处理函数 if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } //如果没有设定自己的oom处理函数,毫不客气的抛出异常 (*my_malloc_handler)(); //设定了就调用oom处理函数 result = malloc(n); //再次尝试申请 if (result) return(result); }}template void* __malloc_alloc_template::oom_realloc(void* p, size_t n){ void (*my_malloc_handler)(); void* result; for (;;) { my_malloc_handler = __malloc_alloc_oom_handler; if (0 == my_malloc_handler) { __THROW_BAD_ALLOC; } //如果自己没有定义oom处理函数,则编译器毫不客气的抛出异常 (*my_malloc_handler)(); //执行自定义的oom处理函数 result = realloc(p, n); //重新分配空间 if (result) return(result); //如果分配到了,返回指向内存的指针 }}
上面代码看似繁杂,其实流程是这样的:
1.我们通过allocate()申请内存,通过deallocate()来释放内存,通过reallocate()重新分配内存。
2.当allocate()或reallocate()分配内存不足时会调用oom_malloc()或oom_remalloc()来处理。
3.当oom_malloc() 或 oom_remalloc()还是没能分配到申请的内存时,会转如下两步中的一步:
(a)调用用户自定义的内存分配不足处理函数(这个函数通过set_malloc_handler() 来设定),然后继续申请内存!
(b)如果用户未定义内存分配不足处理函数,程序就会抛出bad_alloc异常或利用exit(1)终止程序。
看完这个流程,再看看上面的代码就会容易理解多了!
B.二级配置器 _ _default_alloc_template
第二级配置器的代码很多,这里我们只贴出其中的 allocate() 和 dellocate()函数的实现和工作流程(参考侯捷先生的《STL源码剖析》),而在看函数实现代码之前,我大致的描述一下第二层配置器配置内存的机制。
我们之前说过,当申请的内存大于 128 bytes时就调用第一层配置器。当申请的内存小于 128bytes时才会调用第二层配置器。第二层配置器如何维护128bytes一下内存的配置呢? SGI 第二层配置器定义了一个 free-lists,这个free-list是一个数组,如下图:
这数组的元素都是指针,用来指向16个链表的表头。这16个链表上面挂的都是可以用的内存块。只是不同链表中元素的内存块大小不一样,16个链表上分别挂着大小为8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128 bytes的小额区块,图如下:
就是这样,现在我们来看allocate()代码:
static void* allocate(size_t n){ obj* __VOLATILE* my_free_list; obj* __RESTRICT result; //要申请的空间大于128bytes就调用第一级配置 if (n > (size_t)__MAX_BYTES) { return(malloc_alloc::allocate(n)); } //寻找 16 个free lists中恰当的一个 my_free_list = free_list + FREELIST_INDEX(n); result = *my_free_list; if (result == 0) { //没找到可用的free list,准备新填充free list void* r = refill(ROUND_UP(n)); return r; } *my_free_list = result->free_list_link; return (result);};
其中有两个函数我来提一下,一个是ROUND_UP(),这个是将要申请的内存字节数上调为8的倍数。因为我们free-lists中挂的内存块大小都是8的倍数嘛,这样才知道应该去找哪一个链表。另一个就是refill()。这个是在没找到可用的free list的时候调用,准备填充free lists。意思是:参考上图,假设我现在要申请大小为 56bytes 的内存空间,那么就会到free lists 的第 7 个元素所指的链表上去找。如果此时 #6元素所指的链表为空怎么办?这个时候就要调用refill()函数向内存池申请N(一般为20个)个大小为56bytes的内存区块,然后挂到 #6 所指的链表上。这样,申请者就可以得到内存块了。当然,这里为了避免复杂,误导读者我就不讨论refill()函数了。allocate()过程图如下:
学过链表的操作的人不难理解上图,我就不再讲解。下面看deallocate(),代码如下:
static void deallocate(void* p, size_t n){ obj* q = (obj*)p; obj* __VOLATILE* my_free_list; //如果要释放的字节数大于128,则调第一级配置器 if (n > (size_t)__MAX_BYTES) { malloc_alloc::deallocate(p, n); return; } //寻找对应的位置 my_free_list = free_list + FREELIST_INDEX(n); //以下两步将待释放的块加到链表上 q->free_list_link = *my_free_list; *my_free_list = q;}
deallocate()函数释放内存的步骤如下图:
其实这就是一个链表的插入操作,也很简单。不再赘述!上面忘了给链表结点的结构体定义了,如下:
union obj{ union obj * free_list_link; char client_date[1]; };
4.标准库allocator类及其算法
allocator | 定义了一个名为a的allocator对象,它可以为类型为T的对象分配内存 |
---|---|
a.allocate(n) | 分配一段原始的、未构造的内存,保存n个类型为T的对象 |
a.deallocate(p, n) | 释放从T*指针p中地址开始的内存,这块内存保存了n个类型为T的对象,调用deallocate前,用户必须对每个在这块内存中创建的对象调用destroy |
a.construct(p, args) | args被传递给类型为T的构造函数,用来在p指向的内存中构造一个对象 |
a.destory(p) | p为T*类型的指针,此算法对p指向的对象执行析构函数 |
#include #include using namespace std;class Example{public: Example() { cout << "Example default constructor..." << endl; } Example(int x) : a(x) { cout << "Example constructor..." << endl; } ~Example() { cout << "Example destructor..." << endl; } int a = 0;};int main() { allocator alloc; // 使用allocate函数分配一块能够存放5个Example对象的内存空间 Example* p = alloc.allocate(5); // 使用construct函数在第一个位置构造一个Example对象 alloc.construct(p, 1); // 使用construct函数在第二个位置构造一个Example对象 alloc.construct(p + 1, 2); // 使用destroy函数销毁第一个位置的Example对象 alloc.destroy(p); // 使用deallocate函数释放分配的内存空间 alloc.deallocate(p, 5); return 0;}
输出:
Example constructor...Example constructor...Example destructor...
在这个例子中,我们首先创建了一个名为alloc的allocator对象,用于分配Example对象所需的内存。
然后,我们使用alloc.allocate(5)函数分配了一块能够存放5个Example对象的内存空间,并将返回的指针赋值给指针变量p。
接下来,我们使用alloc.construct()函数在刚刚分配的内存空间中构造了两个Example对象。第一个对象使用带参数的构造函数进行构造,并将参数值设置为1;第二个对象也使用带参数的构造函数进行构造,并将参数值设置为2。
然后,我们使用alloc.destroy()函数销毁了第一个位置的Example对象。最后,我们使用alloc.deallocate()函数释放了分配的内存空间。
需要注意的是,在使用allocator类进行内存分配和对象构造时,必须使用alloc.construct()函数来显式地调用构造函数进行对象的构造,并使用alloc.destroy()函数来显式地调用析构函数进行对象的销毁。
参考:STL 之 空间配置器(allocator)
浅析STL allocator
关键词:
126.STL 之 空间配置器(allocator)
乌尔善揭秘《封神第一部》拍摄:最大摄影棚 马跑8秒就出景
新疆“海鲜”上新:沙漠里的澳洲龙虾丰收啦!一斤130元
中国成世界最大投影市场:“中国制造”全球占比超75%
纯燃油车垂死挣扎 今年新车数量占比快跌到1/4了
驾驶员安全与绿色出行:3D可视化技术的双重益处
mysql8 Found option without preceding group错误
React使用useRef调用子组件方法
Go 函数
全铝车身+后置后驱:奇瑞全新suv即将上市 命名“舒享家”
巴奴火锅称羊肉卷确实含有鸭肉成份:向顾客赔偿835.4万元!
机皇预定!曝华为Mate 60 Pro+明天开售:标配16GB内存 512GB起步
“特斯拉强敌”就要来了!Lucid加快进度 计划进入中国市场
华为Vision智慧屏SE3正式开售:2499元起 双120Hz高刷
1199元 小米AR体感运动主机上架:12核双芯+超广角镜头
唯一的双风扇!七彩虹iGame RTX 4070 Ultra限时降价100元
立减70元 29.9元到手!班尼路大牌长袖卫衣大促
土耳其玩家暴怒!PS+订阅费用在土区暴涨近5倍
浙江一村庄出现上千条眼镜蛇 竟是偷偷放生:当地回应
如何从周四就开始过周末?
驾驶特斯拉撞车:林志颖称车祸后理解能力变差 脸部留疤
东风汽车大召回!超110万辆日产汽车被召回:一个阀门的问题
高温连三月 今年或成有记录以来最热年
日系车在国内不好卖了!日产中国8月销量出炉 暴跌34%
中国知网作者服务平台发布试运行:作者可在线申领稿酬
离谱!女子胸口藏16只活蜥蜴入境被查:为印尼斑帆蜥 外来物种危害太大
EVA机甲风:361°3RX-AG1大河原邦男联名球鞋159元(门店699)
产量30年来新低!德国媒体毫不留情批评德国车企:时间不多了
项目管理流程文件,招标支撑文件,项目研发,验收等系列支撑文件
26.高并发服务器
Python名称空间和作用域,闭包函数
业务安全情报第22期 | 不法分子为何盗刷企业短信?
Induction of Design Pattern
减税降费接连出台 积极财政政策加力提效
【财经分析】多空博弈促债市继续盘整 10年期国债利率料上行“有顶”
【新华500】新华500指数(989001)7日跌1.45%
【财经分析】多空博弈促债市继续盘整 10年期国债利率料上行“有顶”
【金融街发布】外汇局:截至8月末外储规模为31601亿美元
不怕买不到首发!京东官宣可提前抢苹果iPhone新品
检测新途径!27年有望实现尿液宫颈癌HPV筛查
10岁男孩落水从山西漂到河北:仰面朝上 “教科书”式自救
美国半导体行业协会总裁:没有一个国家可以扭转芯片供应链 半导体行业需要中国
6999元最强“争气机”!华为Mate 60 Pro南糯紫图赏
沪硅产业:大基金提前终止减持股份计划
从三花猫到癌症治疗:新兴的表观遗传学有哪些机会?
广州海事局启动防热带气旋Ⅲ级响应防范“苏拉”
队报:维拉蒂接近加盟卡塔尔球队阿拉比 德拉克斯勒也可能离队
8月31日汇市观潮:欧元、英镑和澳元技术分析
AIGC说真相|那些年美国扔下的集束炸弹
福建提升防台风应急响应为Ⅱ级 启动防暴雨Ⅳ级应急响应
“谢谢警察叔叔!这是我第一次坐警车!”
跨国零售企业在华业务保持增长
杜锋:波多黎各喜欢出手三分会有长篮板 我们每个人都要努力去抢
三年级上册语文第五单元作文范文
降息了,A股却下跌了?市场在酝酿新的方向!
米干怎么吃 米干怎么吃法
卓越商企服务:主航道业务稳步增长 新赛道构建第二增长曲线
又是一年开学季丨无缝接驳 直通高校 武汉贴心迎新
小鹏最意难平旗舰SUV 新款G9谍照亮相:白内+双风冷无线充
湖南省委政法委:凝心铸魂筑牢根本 实干担当促进发展
先进数通(300541.SZ):主要业务领域,均与华为建立了深入的合作关系
梦到虫子有什么寓意(梦到虫子预示着什么)
美方无理扣留、盘查、遣返中国留学生,中方回应!
国产机器人龙头市场份额 新兴产业成为工业机器人应用新阵地
灵台县职业中等专业学校军训服、校服采购项目中标(成交)结果公告
科锐国际廖萍: 数字化人才将成为VUCA时代企业人才战略的核心
关塔那摩监狱前囚犯揭美军虐囚:放狗咬 剥夺睡眠
windows云电脑
友邦人寿加码银保业务有成效,偿付能力指标待改善
宁夏回族自治区党委原副书记、银川市委原书记姜志刚被“双开”
新突破!广州东部公铁联运枢纽首发汽车专列
直播带货的铠甲与软肋
贵州4地入选现代流通战略支点城市布局建设名单
工商银行喜结良缘金条30克价格今天多少一克(2023年08月31日)
东莞农商行上半年营收净利微增,资产质量继续保持平稳
越素越美!
衡东:800万元助学贷款助学子圆梦
做好垃圾分类,共建绿美花都
打出三张牌激发美食康养文旅消费热
正式成立!泉州市第一医院与上海九院医疗技术协作中心揭牌!
武汉市烟草局:守护成长 “未”爱护航
科创芯片ETF华安(588290)早盘震荡走强,已涨3.02%,盘中成交额破亿元
郑州地铁3号线二期通过初期运营前安全评估
筑牢基层安全“防火墙”盘龙区金辰街道这么做
椰子水价格暴涨4000%!供不应求 订单量上涨数倍
金华一批铁路相关项目有新进展
朱保全回应印力接管万科旗下商业项目进度:目前进展顺利
“共建‘一带一路’十周年:回顾与展望”国际研讨会在霍尔果斯成功举办
以系统观念深入开展主题教育
周末带孩子去哪里玩
山东高速建材集团开展生产车间 “岗位大练兵、技能大比武”活动
79平两房卧室这样设计,绝对是小户型的模仿典范!
这场“零距离”企业恳谈会越开越“有味”
自然资源部:台风“苏拉”逼近 海浪红色预警、风暴潮橙色预警
方便面、汉堡都是垃圾食品?还真不是,什么是垃圾食品呢?
云天化(600096.SH):上半年净利润26.78亿元 同比下降22.74%
20家上市车企披露半年报,超半数净利润增长
中金关注政策组合拳的长期积极影响
开学啦!
军士选晋,为战选才!