SGI STL(四)——_S_chunk_alloc函数解析

news2024/11/26 23:24:49

情况一:内存池剩余空间的大小不满足需要分配的内存空间

假设调用为 _S_chunk_alloc(8, 20), 即希望分配8个20B的内存小块构成的chunk

代码如下

template <bool __threads, int __inst>
char*
__default_alloc_template<__threads, __inst>::_S_chunk_alloc(size_t __size, 
                                                            int& __nobjs)
{
    char* __result;
    size_t __total_bytes = __size * __nobjs; // 需要的内存大小 20 * 8 = 160 
    size_t __bytes_left = _S_end_free - _S_start_free; // 剩余可用空间大小

    
    // 剩余可用空间大小 > 需要的内存大小 ,直接把内存给用户
    if (__bytes_left >= __total_bytes) {
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } 
    else if (__bytes_left >= __size) {
        // 比如需要16字节的内存块,可以从8字节的内存块链表的备用部分取用
        // 即16字节的内存块链表起始地址指向8字节的内存块链表中的后备块
        // 剩余可用空间大小 < 需要的内存大小 但是 > 所需要的单个内存块的大小
        __nobjs = (int)(__bytes_left/__size);
        __total_bytes = __size * __nobjs;
        __result = _S_start_free;
        _S_start_free += __total_bytes;
        return(__result);
    } 
    else { // 需要创建新的chunk块的情况,情况一
        //
        size_t __bytes_to_get = 
	  2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
        // Try to make use of the left-over piece.
        if (__bytes_left > 0) { // 内存碎片处理,接到对应free_list的头部
            _Obj* __STL_VOLATILE* __my_free_list =
                        _S_free_list + _S_freelist_index(__bytes_left);

            ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
            *__my_free_list = (_Obj*)_S_start_free;
        }
        // 分配内存
        _S_start_free = (char*)malloc(__bytes_to_get);
        if (0 == _S_start_free) {}  // if (0 == _S_start_free)
        _S_heap_size += __bytes_to_get;
        _S_end_free = _S_start_free + __bytes_to_get;
        return(_S_chunk_alloc(__size, __nobjs));
    }
}

第一轮进入到else中,创建新的chunk块总共320个字节(_S_heap_size),如下图(这里指针画错了,是8字节的_Obj*指向trunk)

在这里插入图片描述

然后结尾调用 _S_chunk_alloc(__size, __nobjs) 再次进入函数满足__bytes_left >= __total_bytes即(320 >= 160),将内存小块分配给用户,_S_start_free 指针向下移动,即(这里指针画错了,是8字节的_Obj*指向trunk)

在这里插入图片描述

假如又调用 _S_chunk_alloc(8, 20),则把上图下面20个内存块也给用完了,之后再次调用 _S_chunk_alloc(8, 20)的时候就会进入else逻辑,重新计算

__bytes_to_get = 2 * __total_bytes + _S_round_up(_S_heap_size >> 4),结果为60(2 * 20 + 320 >> 4),也就是说要再malloc 60个8B的内存块。

情况2:申请其他字节的内存块时可以复用不同字节的内存小块

如刚刚8B的trunk块还剩余20个内存小块,然后此时来了一个_S_chunk_alloc(16, 20)调用,__bytes_left <= __total_bytes (160 < 320),

但是此时 __bytes_left >= __size,故可以复用备用的内存块即进入代码的 else if (__bytes_left >= __size)分支中执行,将其按照16B进行划分,示意图如下

在这里插入图片描述

若调用_S_chunk_alloc(128, 1),则内存池的情况如下:

在这里插入图片描述

此时再调用 _S_chunk_alloc(40, 20),但是可以看到8B的trunk里只剩余32B的空间,则只能进入else的逻辑,由于剩余空间大于0,则进行内存碎片的处理:把剩余的空间挂接到合适单位字节的trunk块上,即32B的trunk块上,指针做出了如下的变化

在这里插入图片描述

可以看出这种设计方式极大的提高了内存池的利用率,具体代码如下

else { // 需要创建新的chunk块的情况
        //
        size_t __bytes_to_get = 
	  2 * __total_bytes + _S_round_up(_S_heap_size >> 4);
        // Try to make use of the left-over piece.
        if (__bytes_left > 0) { // 内存碎片处理,接到对应free_list的头部
            _Obj* __STL_VOLATILE* __my_free_list =
                        _S_free_list + _S_freelist_index(__bytes_left);

            ((_Obj*)_S_start_free) -> _M_free_list_link = *__my_free_list;
            *__my_free_list = (_Obj*)_S_start_free;
        }
        // 分配内存
        _S_start_free = (char*)malloc(__bytes_to_get);
        if (0 == _S_start_free) {
            size_t __i;
            _Obj* __STL_VOLATILE* __my_free_list;
	    _Obj* __p;
            // Try to make do with what we have.  That can't
            // hurt.  We do not try smaller requests, since that tends
            // to result in disaster on multi-process machines.
            for (__i = __size;
                 __i <= (size_t) _MAX_BYTES;
                 __i += (size_t) _ALIGN) {
                __my_free_list = _S_free_list + _S_freelist_index(__i);
                __p = *__my_free_list;
                if (0 != __p) {
                    *__my_free_list = __p -> _M_free_list_link;
                    _S_start_free = (char*)__p;
                    _S_end_free = _S_start_free + __i;
                    return(_S_chunk_alloc(__size, __nobjs));
                    // Any leftover piece will eventually make it to the
                    // right free list.
                }
            }
	    _S_end_free = 0;	// In case of exception.
            _S_start_free = (char*)malloc_alloc::allocate(__bytes_to_get);
            // This should either throw an
            // exception or remedy the situation.  Thus we assume it
            // succeeded.
 } 

当分配内存失败时,即如下语句失败时:

_S_start_free = (char*)malloc(__bytes_to_get);

进入if (0 == _S_start_free) 分支,进行借内存去找到第一个有可用内存块的trunk【TODO】

如果借内存也失败,那么就尝试 malloc_alloc::allocate ,也就是会调用__malloc_alloc_template::allocate,即

static void* allocate(size_t __n)
{
	void* __result = malloc(__n);
	if (0 == __result) __result = _S_oom_malloc(__n); //
	return __result;
}

如果malloc 调用失败,进入_S_oom_mallocout of memory错误时的处理函数,进入该函数后,可以进行错误的处理,如果用户有设置对应处理函数,就会死循环直到内存分配成功。如果用户没有设置相应的处理函数,就会抛出异常终止程序,代码如下

template <int __inst>
void*
__malloc_alloc_template<__inst>::_S_oom_malloc(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; }
        (*__my_malloc_handler)();
        __result = malloc(__n);
        if (__result) return(__result);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/533744.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ansible 自动化运维工具(二)——Ansible 的脚本(playbook 剧本)

文章目录 一、playbooks 概述以及实例操作1、playbooks 的组成2、操作示例一&#xff1a;3、操作实例二&#xff1a;定义、引用变量4、操作示例三&#xff1a;指定远程主机sudo切换用户5、操作示例四&#xff1a;when条件判断6、操作示例:五&#xff1a;迭代 二、playbook的模块…

怎么把视频压缩变小一点,必须收藏的方法

怎么把视频压缩变小一点&#xff1f;我们发现现在视频在工作中的占比也很大的。当我们拍摄了很多视频后&#xff0c;当然是需要进行后续的编辑和传输啦。但是我们发现视频的进行传输的时候最大的问题就是&#xff0c;视频太大导致无法发送或是发送的时间很慢。现今许多平台都对…

5springboot

SpringBoot 1.SpringBoot是什么 我们知道&#xff0c;从 2002 年开始&#xff0c;Spring 一直在飞速的发展&#xff0c;如今已经成为了在Java EE&#xff08;Java Enterprise Edition&#xff09;开发中真正意义上的标准&#xff0c;但是随着技术的发展&#xff0c;Java EE使…

C++实现图—邻接矩阵,邻接表,深度遍历,广度遍历

目录 1.图的基本概念 2.图的存储结构 2.1邻接矩阵 2.2 邻接表 3.图的遍历 3.1广度优先遍历 3.2图的深度遍历 总结&#xff1a; 1.图的基本概念 图是由顶点集合以及顶点之间的关系组成的一种数据结构&#xff1a;G (V,E),其中顶点集合V{x|x属于某个对象集}是有穷非空集合…

“西湖论剑”四大观察:十年筑梦向未来,数字安全开新局

既有人工智能与安全何去何从的激烈讨论&#xff0c;又有数据安全与数据治理的深度解读&#xff0c;还有数字中国建设背景下安全产业升级的蓝图规划&#xff0c;更有数字安全人才培养的期许与行动……这就是2023 西湖论剑数字安全大会所呈现出的一片热闹景象。 自2012年&#x…

2023全网最全真人总结的常见接口测试面试题,一定不能错过

1、按你的理解&#xff0c;软件接口是什么&#xff1f; 答&#xff1a; 就是指程序中具体负责在不同模块之间传输或接受数据的并做处理的类或者函数。 2、HTTP和HTTPS协议区别&#xff1f; 答&#xff1a; https协议需要到CA&#xff08;Certificate Authority&#xff0c;证书…

理论力学专题:理论力学(物理类)框架

理论力学专题&#xff1a;理论力学&#xff08;物理类&#xff09;框架 拉格朗日方程 虚位移&#xff1a;任意方向的微变化 约束分类&#xff1a; 稳定/不稳定&#xff08;显含时间与否&#xff09;可解/不可解&#xff1a;完整/微分约束&#xff1a; 几何约束&#xff08;完…

F5—创建DDR3内存条DIMM读写测试程序2023-05-16

本文区别于DDR颗粒的配置&#xff0c;记录几个与颗粒配置不同的地方&#xff0c;具体DDR的原理请查看DDR3的应用总结&#xff08;一&#xff09;DDR3的应用总结&#xff08;二&#xff09; 1.确认板卡FPGA型号为xc7k325tffg900 -2&#xff0c;据此创建FPGA工程。 2.添加MIG I…

干货|SPSS方差分析中的简单效应检验(上)

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 今天和大家分享的是包寒吴霜博士生介绍的 SPSS 方差分析中的简单效应检验系列中的第一部分 —— SPSS 方差分析中的简单效应检验&#xff1a;完整教程。 SPSS 是一个入门级的统计分析软件&…

【论文笔记】数据增强系列.1

本文介绍简单数据增强、好处以及常见的增强方式&#xff0c;也介绍几篇关于数据增强的工作&#xff1a; CutMix&#xff08;ICCV2019&#xff09;&#xff0c;ContrastMask&#xff08;CVPR2022&#xff09;&#xff0c;BCP&#xff08;CVPR2023&#xff09;。 数据增强简介&a…

Nginx缓存优雅清除缓存

1.Nginx缓存 前面我们知道Nginx可以对浏览器缓存进行配置&#xff0c;让一些静态资源缓存到用户本地存储&#xff0c;以提高页面的响应速度&#xff0c;也能降低服务端的压力。浏览器执行缓存的流程如下&#xff1a; 试想一下&#xff0c;如果用户主动清空了本地的浏览器缓存&…

HNU-操作系统-讨论课6

讨论题目&#xff1a; 以一种程序设计语言为例&#xff0c;如 Java、C、Python等介绍其为实现并发控制提供的各种锁机制

doxygen: 在Windows上源码编译(施工中)

文章目录 1. 目的2. 思路3. 安装 Chocolatey4. 用 choco 安装 bison 和 flex安装 gs:安装 libiconv 5. 编译报错 1. 目的 在 windows 上源码编译 doxygen&#xff0c; 改代码加功能。 2. 思路 doxygen 依赖 flex 和 bison&#xff0c; 手动编译 flex 和 bison 很麻烦可以用…

【华为OD机试c++】九宫格游戏【2023 Q1 A卷|200分】

■ 题目描述 九宫格是一款广为流传的游戏,起源于河图洛书。 游戏规则是:1到9九个数字放在33的格子中,要求每行、 每列以及两个对角线上的三数之和都等于15. 在金麻名著《射雕英雄传》中黃蓉曾给九宫格的一种解法,口诀: 戴九恩一,左三右七,二四有肩,八六为足,五居…

通过命令行体验长安链

通过命令行体验长安链 1 、概述2、环境依赖2.1、硬件依赖2.2、软件依赖2.3、git安装2.4、golang安装2.5、gcc 3、环境搭建3.1、源码下载3.2、 源码编译3.3、编译及安装包制作3.4、启动节点集群3.5、查看节点启动使用正常 官方文档 https://docs.chainmaker.org.cn/v2.3.1/html/…

亿信BI专有名词讲解

数据库连接池主题域/主题集/主题表维/ 维表报表模板组件容器布局计算参数分析区浮动门户EasyOlap领导驾驶舱(Dashboard) 1.数据库连接池 连接池就是存储资源和数据的地方。BI一定会有一个缺省连接池&#xff0c;BI服务器的系统表都是在缺省连接池下面&#xff0c;初次部署BI服…

30.SSM框架整合

目录 一、SSM框架整合。 &#xff08;1&#xff09;核心笔记。 &#xff08;1.1&#xff09;Spring、SpringMVC、MyBatis三者的配置。 &#xff08;1.2&#xff09;请求字符集格式与响应字符集格式。 &#xff08;2&#xff09;原始方式整合。 &#xff08;2.1&#xff…

路径规划算法:基于郊狼算法的路径规划算法- 附代码

路径规划算法&#xff1a;基于郊狼优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于郊狼优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法郊狼…

带你实现初阶扫雷小游戏—【C语言】

目录 1. 扫雷游戏实现的思路 注意点1 注意点2 2. 函数实现扫雷功能 2.1 初始化棋盘 2.2 显示棋盘 2.3 设置雷 2.4 排查雷 2.5 返回附近雷的个数 3.源码 3.1 game.h 3.2 game.c 3.3 test.c 1. 扫雷游戏实现的思路 注意点1 我们这里拿9*9的棋盘&#xff08;其中…

Java的基操,基操(二)

&#x1f525;常量(Constant)&#x1f525;基本数据类型(primitive data type)&#x1f525;整型&#x1f525;浮点型(Floating Point Number)&#x1f525;字符型&#x1f525;布尔型(boolean)&#x1f525;运算符(operator)&#x1f525;逻辑运算符&#x1f525;数据类型的转…