【STL】SGI空间配置器(一):一级空间配置器

2023-11-01

今天看了STL中的空间配置器,写一篇博客小小的总结一下。

STL空间配置器的产生

在实际的软件开发中,当我们使用C++中的malloc、new、free和delete时,我们不可避免的会因为程序的需求,使用很多的小内存块,这个过程是不一定能够控制好的,例如下面的场景
这里写图片描述
而且一直调用malloc和new产生小块内存不光会产生内存碎片,而且系统调用会产生性能问题。

内碎片与外碎片

内碎片:因为内存对齐/访问效率(CPU取址次数)而产生 如 用户需要3字节,实际得到4或者8字节的问题,其中的碎片是浪费掉的。
外碎片:系统中内存总量足够,但是不连续,所以无法分配给用户使用而产生的浪费

于是为了解决内存碎片和系统性能等问题,STL的SGI空间配置器就因此而产生了,它一共有两层空间配置器,分别是第一级空间配置器和第二级空间配置器。第一级空间配置器被定义为__malloc_alloc_template

template <int inst>    //inst 为预留参数,现在还没有什么具体作用
class __malloc_alloc_template

第二级空间配置器被定义为__default_alloc_template

template <bool threads, int inst>   //threads用于多线程参数下,现在暂不讨论
class __default_alloc_template

今天我们主要来谈一下第一级空间配置器。

源码分析

oom—out of memory
处理内存不足的函数和函数指针

private:

static void *oom_malloc(size_t);

static void *oom_realloc(void *, size_t);

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
    static void (* __malloc_alloc_oom_handler)();
#endif

下面的函数负责开辟和释放空间

static void * allocate(size_t n)    
{
 //调用malloc开辟空间
    void *result = malloc(n);
 //如果开辟空间失败调用处理内存不足的函数
    if (0 == result) result = oom_malloc(n);
 //开辟空间成功则返回这块空间
    return result;
}

static void deallocate(void *p, size_t /* n */)
{
//直接调用free()函数释放这块空间
    free(p);
}

static void * reallocate(void *p, size_t /* old_sz */, size_t new_sz)
{
//调用realloc()开辟空间
    void * result = realloc(p, new_sz);
//开辟空间失败调用处理内存不足的函数
    if (0 == result) result = oom_realloc(p, new_sz);
//开辟空间成功则返回这块空间
    return result;
}

//这里模仿C++ operrator new 的set_new_handler机制

static void (* set_malloc_handler(void (*f)()))()
{
    void (* old)() = __malloc_alloc_oom_handler;
    __malloc_alloc_oom_handler = f;
    return(old);
}

既然说到了这里,下面我们来谈一谈set_new_hanlder机制
参考《Effective C++》条款49。
在C++中我们用operator new来开辟一块空间:
当operator new申请一个内存失败的时候,它会进行如下的处理步骤:
1、如果存在客户指定的处理函数,则调用处理函数(new_handler),如果不存在则抛出一个异常。new_handler的模型为:void (*new_handler)()。
2、继续申请内存分配请求。
3、判断申请内存是否成功,如果成功则返回内存指针,如果失败转向处理步骤1

为了指定这个用以处理内存不足的函数,客户必须调用set_new_hanlder,它在标准模板库中是下面这么定义的:

namespace std
{
   typedef void (*new_hanlder)();//newhanlder其实是一个函数指针
   new_handler set_new_hanlder(new_hanlder p) throw();
   //set_new_hanlder其实是一个不能够抛出异常的函数
}

下面我们来说一下怎么指定这个new_hanlder

class A
{
public:
    static void OutOfMemory()  //用户自己定义处理内存不足的函数
    {
        //...
    }

    static std::new_handler set_new_hanlder(std::new_handler p) throw();
    //将函数名传给new_hanlder
};

当operator new无法满足内存申请时,它会不断调用new_handler函数就是用户自己定义的OutOfMemory(),直到系统能够找到足够的内存

现在我们知道了new操作失败后,系统地大概处理流程,以及怎么设置用户自定义处理函数,但是我们究竟可以在new_handler中做些什么处理呢?
1、删除其它无用的内存,使系统具有可以更多的内存可以使用,为下一步的内存申请作准备。
2、设置另外一个new_handler。如果当前的new_handler不能够做到更多的内存申请操作,或者它知道另外一个new_handler可以做到,则可以调用set_new_handler函数设置另外一个new_handler,这样在operator new下一次调用的时候,可以使用这个新的new_handler。
3、卸载new_handler,使operator new在下一次调用的时候,因为new_handler为空抛出内存申请异常。
4、抛出自定义异常
5、不再返回,调用abort或者exit退出程序

现在我们回归正轨看一下SGI空间配置器是如何处理内存不足的

//初始化hanlder

#ifndef __STL_STATIC_TEMPLATE_MEMBER_BUG
template <int inst>
void (* __malloc_alloc_template<inst>::__malloc_alloc_oom_handler)() = 0;
#endif
template <int inst>
void * __malloc_alloc_template<inst>::oom_malloc(size_t n)
{
    void (* my_malloc_handler)();
    void *result;

    for (;;) {
    //这里是将my_malloc_hanlder函数指针指向用户定义的内存不足处理函数
        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);
  //如果内存空间分配不成功,则反复的执行内存不足处理函数
    }
}

realloc的内存不足处理函数在这里也做了与上面的malloc内存不足处理函数一样的事情

template <int inst>
void * __malloc_alloc_template<inst>::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; }
        (*my_malloc_handler)();
        result = realloc(p, n);
        if (result) return(result);
    }
}

现在我们应该对SGI STL的一级空间配置器有所了解了,它用malloc()函数分配空间,如果分配成功直接返回这块空间,如果空间分配不成功并且用户自己定义了内存不足处理函数,就调用内存不足处理函数,然后在尝试去开辟空间,如果内存还是分配不成功就继续调用内存不足处理函数直到内存成功分配为止,如果用户没有定义内存不足处理函数,那么就会抛出一个异常。

这是SGI中的第一级空间配置器,下期我们还会分析第二级空间配置器,体会STL所存在的价值!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STL】SGI空间配置器(一):一级空间配置器 的相关文章

随机推荐

  • H5页面跳转到微信公众号首页

    H5页面跳转到微信公众号首页 1 需求背景 微信公众号 客户端 网页需要用户关注才能进行活动 因此需要引流到公众号进行关注操作 在多篇文章无法找到关键的一个解决点 主要是在阐述如何复制公众号首页的链接 2 具体实现 首先 找到公众号的一个首
  • 【点云下采样/抽稀】python-pcl:pcl::VoxelGrid::applyFilter

    这篇博客将介绍如何使用python pcl对点云las laz进行下采样 抽稀 可以根据设置的参数决定下采样到元数据的90 80 60 或者40 不会完整的按这个梯度递减 但参数rate顺序下降 基本能大致达到这个概率 下采样设置的voxe
  • mysql添加表注释、字段注释、查看与修改注释

    mysql 一 基础知识 1 创建表的时候写注释 create table test1 field name int comment 字段的注释 comment 表的注释 2 修改表的注释 alter table test1 comment
  • Ubuntu root用户界面登录设置

    Ubuntu下用户登录界面默认是没有root权限登录的 以下设置可以在用户界面添加root权限登录 sudo vim usr share lightdm lightdm conf d 50 ubuntu conf greeter show
  • 搭建Android开发环境 以及 ionic 编译安卓app步骤

    1 下载安装JDK 下载地址 https www oracle com technetwork java javase downloads jdk8 downloads 2133151 html 安装好后 配置系统环境变量 控制面板 系统和
  • html5文本框设置圆角,css如何设置圆角边框?

    圆角边框是css3新增属性 在圆角边框出现之前 前端开发有的采用整块的圆角图片作为背景 有的采用小的圆角图片分别放在元素的四角 非常麻烦 下面我们来看一下如何使用css设置圆角边框 圆角边框 border radius 的基本用法 圆角边框
  • Java通过网络url直接读取文件内容

    public void readFileFromUrl String filePath throws Exception URL url new URL filePath HttpURLConnection urlConnection Ht
  • HWnd和CWnd的获取函数

    顺便记录一下有关窗口对象指针和窗口句柄相关的函数 Win32 API函数对窗口的操作总是需要一个窗口句柄 hWnd 来指向需要操作的对象 比如 SetWindowPos hWnd 而MFC内 窗口句柄已经包含在对象成员内 需要的是指向窗口对
  • R语言设置当前工作文件夹

    getwd 这个函数用于显示当前工作空间的路径 setwd 用于重新设置当前工作文件夹 list files 列出当前文件夹的子目录 list files path 列出指定路径的子目录 source R 加载R文件 gt getwd 1
  • seam-gen 增加messages_zh_CN.properties

    新建一个Generic Exporter 具体添加的属性如下 File Pattern messages zh CN properties For each entity herbernatetool util toolclass org
  • A simple yet effective baseline for 3d human pose estimation

    A simple yet effective baseline for 3d human pose estimation 主要工作 在以往的人体3D关键点检测的方法中 主要有两种 一种是构造end to end的网络 直接实现输入普通图像
  • 与HTTP(Restful API)对比,gRPC的优势

    gRPC是什么 gRPC是什么可以用官网的一句话来概括 A high performance open source universal RPC framework 所谓RPC remote procedure call 远程过程调用 框架
  • Qt七种信号与槽关联方式小结

    Qt七种信号与槽关联方式 1 F4 F3 ui界面编辑方式 在UI界面按下F4按键 会进入信号与槽的编辑界面 可看到左侧工具栏全部变为灰色 无法进行部件的选择 左键点击界面中已经添加好的部件 然后进行拖拽即可建立信号与槽的关联 按下F3即可
  • Docker安装 Nacos 单机超详细教程(配合宝塔)

    一 事前准备 CentOs系统 安装了宝塔面板 安装了docker 云平台防火墙里开放8848端口 官网地址 宝塔 安全放行8848端口 记得使用firewall cmd list port 查看一下linux有没有开放nacos的8848
  • Electron的安装与使用

    Electron的安装与使用 一 Electron的安装 1 使用脚手架创建 2 electron的使用 3 总结 二 打包并分发应用程序 通过Electron Forge打包 三 如何在VSCode中跑Electron项目 四 使用VSC
  • 【Unity】Post-process后处理之Lens Distortion

    安装组件 Ambient Occlusion 环境光遮蔽 Anti aliasing 抗锯齿 Auto Exposure 自动曝光 Bloom 柔光 Chromatic Aberration 色差 Color Grading 颜色分级 De
  • 用递归法求一个整数数组a中的最大元素C++(超级灵活,且实用)

    前言 最近在学算法 我看书上的代码实现部分太简陋了 不能完全理解 还是自己敲一遍最有效 此代码包含递归算法和调用随机数生成数组方法 我觉得还是蛮简介有效的 把两者结合起来 优化了输入效率 执行效率 完整代码 include
  • 十一、Linux驱动之platform总线设备驱动

    1 基本概念 从Linux2 6开始Linux加入了一套驱动管理和注册机制 platform平台总线驱动模型 platform平台总线是一条虚拟总线 platform device为相应的设备 platform driver为相应的驱动 与
  • JQuery

    JQuery 一 本地存储 特性 1 数据存储在用户浏览器中 2 设置 读取方便 甚至页面刷新不丢失数据 3 容量较大 sessionStorage约5M localStorage约20M 4 只能存储字符串 可将对象JSON string
  • 【STL】SGI空间配置器(一):一级空间配置器

    今天看了STL中的空间配置器 写一篇博客小小的总结一下 STL空间配置器的产生 在实际的软件开发中 当我们使用C 中的malloc new free和delete时 我们不可避免的会因为程序的需求 使用很多的小内存块 这个过程是不一定能够控