当前位置: 首页 > 编程日记 > 正文

一种内存池管理技术

本文介绍一种内存池管理技术。
在m公司工作了4年多,一直负责内存池模块问题的处理,比如内存越界,data abort 系统异常的处理,本文加以总结,以便后续参考。
读本文之前,先有个约定,本文中提到的pool指的就是内存池,buffer就是内存池中的一个存储单元,一个pool包含多个buffer。

1. 内存池整体规划

首先介绍下内存池的布局,pool共12个,pool[0]包含930buffer,每个buffer的大小是 32 bytes, 12个pool的详细信息见下图:
在这里插入图片描述

2. buffer 的布局

2.1 buffer示意图
以pool[0] 为例介绍一下buffer的布局,示意图(将来画一个漂亮的图替代之)如下:
在这里插入图片描述
在这里插入图片描述
上图左半部分: pool[0]包含930个buffer,每个buffer 的大小是32bytes.
上图右半部分:是buffer[3]的内存布局,可见除了用户申请的32个bytes之外,还有20个bytes的额外开销(管理成本),这20个bytes的额外开销包含5个4bytes: 4x4bytes 位于分配的内存之前(图中用1,2,3,4表示),1x4bytes位于分配的内存之后。

头部的4x4bytes作用解释
1(POOL_NEXT)Next available buffer address如果当前buffer的状态为free,指的是本pool中下一个可用buffer的地址.如果当前状态的状态是allocated, 为magic number:0x50555345
2(POOL_ID)指向当前buffer所属pool 的info当前pool中的所有buffer 中的这一地址存储一样的地址。(后面会详细介绍pool info)
3(HEAD)固定魔数: 0XF1F1F1F1Header
4(TASK)当前buffer所属的owner当前buffer是被那个task申请的
尾部的1x4bytes作用解释
1Buffer的footer后2个buffer固定0xF2F2,前2个buffer位当前buffer所在pool的index.上图为:0x03F2F2

要注意一点如果用户申请的内存小于32个bytes, 我们也会分配一个32个bytes的buffer给用户。 用户申请n个bytes, n<32, 系统会将[n+1,n+4]这4个bytes设置为0xF2F2F2F2, 我们把这个魔数叫做Footer. 上图中用户实际申请16个bytes,内存系统会将17直20这4个bytes设置为0xF2F2F2F2.

2.2 Trace32 恢复出的buffer布局
0x02F1F2F2: 是第0x02F1个buffer

接下来的52个bytes[0x649AA870, 0x649AA8A4]为第0x02F2个buffer的地址范围,可以对照上面的解释详细分析下这52个bytes:
0x50555345: 这个buffer的状态为allocated.
0x649A0EFC: 这个地址存储的是此buffer所属内存池的pool info.
0xF1F1F1F1: Header,
0x64B1B448: 这个buffer属于哪个task分配的。
[0x649A A880, 0x649A A89F]:这32个bytes 为实际分配的内存,其中有2个0xF2F2F2F2, 所以可以推测出用户实际申请的real size 为16 bytes 或者 24 bytes, 但是从目前的信息无法确实是16还是24. (参考第六节:内存系统的不足)
0x02F2F2F2:指示这是第0x02F2个buffer.
在这里插入图片描述

2.3 申请和释放buffer时的错误检查
通过以上分析,每个buffer有20 bytes的额外开销,这些开销对后续定位内存越界有很大的帮助。内存管理系统在用户申请/释放buffer时,会对buffer的布局进行检查。
Pool初始化完后内部buffer如下。在分配内存时会检查 PM_NEXT/POOL_ID/HEAD信息是否正确,如果存在问题,会报异常出来,我们称简称这种错误为HEAD被踩.
在这里插入图片描述

Buffer被分配出去(Allocated)后的布局如下,在释放buffer时除了检查上述的HEAD被踩的情况,还需要检查是否FOOTER被踩
在这里插入图片描述

被踩类型原因
HEAD 被踩前一个buffer发生越界,需要检查前一个buffer的内存布局是否正确。如果前一个buffer的HEAD也被踩,需要继续向前查前一个buffer.
FOOTER被踩(HEAD未被踩) 当前buffer越界,需要检查当前buffer所属task的上下文。

3. pool info介绍

第2节中有介绍每个buffer的头部的4*4bytes中,有4个bytes(POOL_ID)存储的是当前buffer所属pool 的信息,pool结构体细节如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

4. buffer statistics

第3节中提到了在pool的信息中存储了buffer的统计信息,也就是buffer的history,存储了3个数组。这3个数组中也包含了当前buffer的使用信息,这3个数组可以理解为一个环形队列,由于buffer只有2中状态:ALLOCATED/FREE, 所以这3个数组中的buffer_status依次只有如下可能:ALLOCATED/FREE/ ALLOCATED 或者FREE/ALLOCATED/FREE, 根据owner_task或buffer_status就可以推导出那个node 属于当前buffer的信息。
下图为buffer[860]对应的buf_statistics中的3个历史节点,通过以上分析,可知node[2]为当前buffer 对应的节点。
在这里插入图片描述
如果这个队列中出现了2个ALLOCATED或者FREE依次出现,就表明程序存在bug。举例:History node[0].buffer_status等于ALLOCATED,History node[1].buffer_status也等于ALLOCATED, 则程序存在bug.

5. pool中可用的buffer链表

第3节中提到了在pool的信息中存储了可用buffer的链表available_list,另外在第2节中提到的buffer头中的POOL_NEXT,这2者之间存在关联,我们摘取Pool中的buffer初始化状态:
在这里插入图片描述
user_ptr是buffer中实际内存的地址(不包含buffer头部的16 bytes (0x10)的额外开销),PM_NEXT是buffer中开头地址(包含buffer头部的16bytes的额外开销)
buffer[n]中的PM_NEXT+0x10 指向buffer[n-1]中user_ptr
比如,buf[8]中的PM_NEXT(0x635E 3824 + 0x10)指向buf[7]中的user_ptr(0x635E 3834)
通过上图可以推测,以pool[0]为例(930个buffer), pool[0]初始化时,pool info中的available_list存储的是buffer[929]中的user_ptr, 当用户第1次申请buffer(小于等于32 bytes)时, 会将buffer[929]中PM_NEXT+0x10赋值给available_list,依次类推….,所以pool中的buffer是从后往前依次使用的。
扩展:释放内存时,内存系统怎么处理呢?
一种可能是:假设buffer[x]要释放,当前available_list.head 指向的是buffer[800], 伪代码如下:
buffer[x].PM_NEXT = buffer[800].user_ptr – 0x10;
avaialble_list.head = buffer[x].user_ptr;
这种做法的特点是:被释放的内存会很快被再次分配出去
还有一种可能是:假设buffer[x]要释放, available_list.tail 指向的是buffer[0], 伪代码如下:
buffer[0].PM_NEXT = buffer[x].user_ptr – 0x10;
buffer[x].PM_NEXT = NULL;
这种做法的特点是:被释放的内存会最后被分配出去,符合FIFO. 还记得pool_info.pm_fifo_suspend吗?推测和内存释放的策略有关系。

6. 内存系统中的不足和可改善之处

 第5章提到的available_list,其实可以不用链表,如果为了节省空间的话,只需要存储一个地址即可:指向下一个可用的buffer的user_ptr. 但是这样做的缺点时,如果buffer中的PM_NEXT由于内存越界被踩的话,可用buffer链表可能会断掉。

 此内存系统在free buffer时,没有clean buffer. 从已经分配buffer中存在多个0xF2F2F2F2就证明了这一点。 难道是为了提高程序的运行效率?

尽可能少的报异常出来
如果只是踩了buffer自己的Footer(0xF2F2F2F2),是不是可以考虑不报异常出来,尽可能让程序运行下去呢?提高用户体验。

 第1节提到的每个pool中的buffer个数是固定的,所以每一代产品都需要评估这个数量是否够用。如果buffer被申请完了,再申请的话,就会报错(pool_info.task_waiting推测与此有关,如果申请不到,task是否需要等待,此内存池系统无内存回收机制)。另外,pool_info.buf_statistic.time_stamp存储了buffer申请的时间,是不是可以考虑,如果某个buffer长久不释放的话,需要让buffer申请者检查下程序是否存在bug, 从而控制buffer的无限制扩大。

7. 扩展

use_after_free检查
buffer头中的PM_NEXT,如果不是0x50555345,则表示buffer为free状态,如果这时要访问此buffer,则发生use_after_free.
可以考虑在debug版本下打开此功能。release版本下打开会影响性能。

相关文章:

企业支付宝账号开发接口实现

转载自&#xff1a;http://my.oschina.net/xshuai/blog/313809 关于即时到账的开发。审核通过。简单测试如下。 希望看的可以收藏或者赞一下哦。 1:拥有自己的支付宝企业账号。去产品商店选择适合自己的方案。并签约合同。 2:选择合适的商家收款产品并去签约。填写相应的信息 3…

Fastadmin管理Mysql_FastAdmin-CMS模版制作(6)-正式部署

一、工具信息介绍(1)服务器系统&#xff1a;CentOS7.2 64位系统&#xff1b;(2)服务器面板&#xff1a;宝塔&#xff0c;官网地址&#xff1a;https://www.bt.cn/&#xff1b;(3)PHP7.2&#xff1b;(4)mysql5.6&#xff1b;(5)Nginx&#xff1b;二、运行环境安装(1)进入宝塔官网…

使用微软提供的Office Online实现Office文档的在线查看,编辑等功能

使用微软提供的Office Online平台只需要一个网址即可在线查看Xls,doc,PPT等文档http://view.officeapps.live.com/op/view.aspx?src要查看的文档地址在线编辑需要登录live.com并从onedrive中打开或新建文档也可以来自在线模板(下面的Excel来自Excel Online模板&#xff0c;编辑…

HDU(1847)Good Luck in CET-4 Everybody!

利用PN分析求解此题。递推下去会发现3和3的倍数都是P点。 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <set> using namespace std; int main() {int n;while(~scanf("%d",&n)){i…

uboot引导kernel - 1 - Flash的分区

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题1&#xff1a;Flash的分区相关问题 在 上述步骤1/2/4 中都提到了从启动介质(iNand/SD)中读取uboot/kernel到SRAM/DDR中&#xff0c;那么具体从启动介质的什么位置分别读取呢&#xff1f;  上述步骤1中&#xff0c;iROM的…

fedora mysql默认密码忘记_Linux fedora 24 忘记密码图形化界面修改root密码的方法

方法及其简单&#xff0c;只需要两步即可&#xff1a;1、第一步&#xff1a;打开终端&#xff0c;输入sudo su命令。–此处的密码为普通用户的密码&#xff0c;也就是开机时输入的密码。2、第二步&#xff1a;直接sudo passwd root就重置了roor密码了。此时输入新的密码即可&am…

Java Web项目结构

Java Web项目结构&#xff08;一般&#xff09; 1、Java src 2、JRE System Library 3、Java EE 6 Libraries 4、Web App Libraries 5、WebRoot 版权声明&#xff1a;本文博客原创文章&#xff0c;博客&#xff0c;未经同意&#xff0c;不得转载。转载于:https://www.cnblogs.c…

WTForms 小计1 forms

2019独角兽企业重金招聘Python工程师标准>>> 定义 from wtforms import Form, StringField, validators class MyForm(Form):first_name StringField(uFirst Name, validators[validators.input_required()])last_name StringField(uLast Name, validators[vali…

day32-1 事件Event

事件Event-线程 每一个线程都是独立运行且状态不可预测。你把一个任务丢到子线程中&#xff0c;这个任务将异步执行&#xff0c;如何获取到这个任务的执行状态&#xff1f;使用threading库中的Event对象。对象包含一个可由线程设置的信号标志&#xff0c;线程直到等到该标志为真…

uboot引导kernel - 2- uboot/kernel需要放在DDR什么位置的问题

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题2&#xff1a; uboot阶段DDR的分区的问题 上述步骤2和步骤4中&#xff0c;有将uboot/kernel拷贝纸DDR的步骤&#xff0c;具体要拷贝到DDR的什么位置呢&#xff1f; 分清楚这两个概念&#xff1a; 链接地址&#xff1a;链接…

java ftp pasv_Ftp主动模式和被动模式以及java连接ftp模式设置

FTP的主动模式与被动模式FTP服务器使用20和21两个网络端口与FTP客户端进行通信。FTP服务器的21端口用于传输FTP的控制命令&#xff0c;20端口用于传输文件数据。FTP主动模式&#xff1a;FTP客户端向服务器的FTP控制端口(默认是21)发送连接请求&#xff0c;服务器接受连接&#…

Python2.7 安装numpy报错解决方法

Windows 10下用pip安装numpy包报错&#xff1a; Microsoft Visual C 9.0 is required Unable to find vcvarsall.bat Get it from http://aka.ms/vcpython27 通过报错提示信息&#xff0c;打开http://aka.ms/vcpython27会跳转到Microsoft Visual C Compiler for Python 2.7的下…

异常The Struts dispatcher cannot be found. This is

2019独角兽企业重金招聘Python工程师标准>>> 原因&#xff1a;struts2的过滤器映射路径写错 解决方案&#xff1a;在web.xml中配置struts2的过滤器如下&#xff1a; <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*&…

UNDO表空间损坏,爆满,ORA-600[4194]/[4193]错误解决

模拟手工删除UNDO表空间 在ORADATA 中把UNDOTBS01.DBF 删除模拟启库SQL> STARUP;*第 1 行出现错误:ORA-01157: 无法标识/锁定数据文件 2 - 请参阅 DBWR 跟踪文件ORA-01110: 数据文件 2: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\UNDOTBS01.DBF利用系统本身的默认手动管理 MAN…

uboot引导kernel - 3 -uboot给内核传参详解

uboot中执行theKernel函数后&#xff0c;kernel正式启动。如下函数&#xff0c;我们发现有3个参数。 1. 参数 0&#xff1b; 2. 参数machid; 如下code 中获取machid, gd是个全局变量. 2.1 bi_arch_number是board_info中的一个元素&#xff0c;含义是&#xff1a;开发板的机器…

hdu 1166 敌兵布阵(树状数组)

题意&#xff1a;区间和 思路&#xff1a;树状数组 #include<iostream> #include<stdio.h> #include<string.h> using namespace std;int n,c[50005];int lowbit(int i){return i&-i; }void update(int i,int val){//更新函数while(i<n){//注意这个n的…

java jdbc 表存在_使用JDBC查询是否存在某表或视图,按月动态生成表

查询数据库是否有某表的存在&#xff0c;主要用的就是Connection对象对元数据的操作&#xff0c;代码很简单&#xff0c;贴出来大家参考。/*** 查询数据库是否有某表* param cnn* param tableName* return* throws Exception*/SuppressWarnings("unchecked")public b…

linux串口驱动分析

linux串口驱动分析硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器&#xff08;UART&#xff09;提供了三个独立的异步串行 I/O&#xff08;SIO&#xff09;port&#xff0c;每一个port都能够在中断模式或 DMA 模式下操作。UART 使用系统时钟能够支持最高 115.2Kbps 的波特…

计算TD-LTE DL 峰值速率的工具和相关参数

前一段时间测试DT 基站&#xff0c;需要配置TDD LTE cell 的UDC、TM模式来验证不同组合下的下行峰值速率&#xff0c;趁此机会我用excel写了一个计算下行峰值速率的工具。工具上传至我的github: https://github.com/greenricky/tdlte_dl_rate 计算峰值速率的常用办法是参考36.2…

java配置中心开源项目_配置中心搭建(spring-cloud-config-server)

1.github创建配置库2.配置服务端①创建项目②导入jarorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testorg.springframework.cloudspring-cloud-starter-netflix-eureka-clientorg.springframework.cloudspring-cloud-config-…

detection in video and image

video中的detection&#xff0c;背景更加复杂&#xff0c;目标更加不聚焦&#xff0c;同时由于图片分辨率低于图像&#xff0c;因此更加难做。 image中的Detection,背景相对简单些&#xff0c;目标更加聚焦&#xff0c;同时图片分辨率高&#xff0c;因此更加容易些。 转载于:ht…

烂泥:U盘安装Centos6.5

本文首发于烂泥行天下。使用U盘安装Centos6.5&#xff0c;需要以下几个步骤&#xff1a;1、 制作U盘linux系统2、 设置服务器BIOS3、 安装Centos&#xff0c;注意引导分区的安装首先要把U盘做成linux启动盘。网上有关这方面的软件比较多&#xff0c;在此我使用的是WinSetupFrom…

http status 汇总

http status 汇总 常见HTTP状态码 200 OK301 Moved Permanently302 Found304 Not Modified307 Temporary Redirect400 Bad Request401 Unauthorized403 Forbidden404 Not Found410 Gone500 Internal Server Error501 Not Implemented100 Continue 初始的请求已经接受&#xf…

hdu 4278 2012天津赛区网络赛 数学 *

8进制转为10进制 1 #include<cstdio>2 #include<iostream>3 #include<algorithm>4 #include<cstring>5 #include<cmath>6 #include<queue>7 #include<map>8 using namespace std;9 #define MOD 1000000007 10 const int INF0x3f3f3f…

slub object 内存布局

我在 https://blog.csdn.net/wowricky/article/details/83218126 介绍了一种内存池&#xff0c;它的实现类似于linux 中打开slub_debug (1. make menuconfig: Kenel hacking -> Memory Debugging, 2. comand line中传入slub_debugPZU) 时slub 对象池。 首先我们先看一下slub…

java wait abc_java----wait/notify

解释wait/notify必须配合synchronized使用democlass NotifyStop2 {private final Object lock new Object();public void add(String s) throws InterruptedException {Thread.sleep(1000);synchronized (lock) {System.out.println("add notify qian");//唤醒其他线…

hdu-1166敌兵布阵

这个题目就是考察线段树的基本用法&#xff0c;我自己打了代码&#xff0c;其实就是照模板来的&#xff0c;大概思想已经弄懂了。用c不能过&#xff0c;说我超时&#xff0c;就改成c的读入读出&#xff0c;这坑爹的过了。我最爱的c&#xff0c;你肿么了。。。 这是ac的代码&…

Android数据存储(三)——SQLite

如果需要一个更加健壮的数据存储机制&#xff0c;则需要使用一个关系型数据库&#xff0c;在Android上&#xff0c;则为SQLlite。 SQLite的特点&#xff1a;轻量级、嵌入式的、关系型数据库。可移植性好&#xff0c;易使用&#xff0c;小&#xff0c;高效且可靠&#xff0c;与使…

3GPP组织和协议概述

3GPP组织概述 1. TSG/WG 3GPP是以工作组开展工作的&#xff0c;目前有3个大的技术规范组&#xff1a;RAN, SA, CT, 这一级别的工作组英语写为 TSG (Technical Specification Group)。每个TSG下面又分了很多工作组(WG: work group). 详见下表&#xff1a; https://www.3gpp.or…

mysql被拖垮_说几个拖垮系统的小细节!

本文首发于个人微信公众号《andyqian》,期待你的关注&#xff01;前言有好几天没有更新了&#xff0c;期间确实比较忙些&#xff0c;以至于周末也没休息。在这期间&#xff0c;感触还是蛮深的。现在碎片化的想法等整理好后&#xff0c;再以文章的形式分享出来。今天要说的是另外…