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

内存分配器memblock【转】

目录(?)[-]

  1. 背景
  2. Data structure
  3. memblock initialization
  4. memblock API
  5. memory和reserved region
    1. memblock_reserved
    2. memblock_alloc
    3. memblock_free

背景

在Linux内核开发过程中, 多少都会存在一个patch, 引入了远超预期的麻烦. 内核2.6.34开发过程中, 这个奖项非CONFIG_NO_BOOTMEM莫属

bootmem本身是个简单的,低级的内存分配器. 在引导程序的初期用来分配内存. 有人可能会想, 没有必要再增加一个内存分配器, 但是由于内存管理代码在被调用前需要很多内核功能都准备好, 要想在启动初期使用内存管理代码会大大增加内存管理的复杂性. 在x86架构上, 会首先使用early_res机制接替BIOS e820的工作, 然后再交给架构独立的bootmem分配器, 最后才是全功能的buddy allocator

YingHai LU认为可以把bootmem从这个过程中去掉, 简化这个过程. 结果就是, 增加了一堆patch来扩展early_res机制, 把本该交给bootmem做的事情都做了, 然后直接到buddy分配器. 这些修改被合入了2.6.34, 老的基于bootmem的代码仍然保留. CONFIG_NO_BOOTMEM用来控制使用哪个分配器, 缺省情况下并不使用bootmem

一切本该非常美好, 但是随着kernel rc版本的发布, 新分配器测试陆续爆出很多问题, Linus发了一封邮件要求revert掉整个patch. 虽然简化代码这个注意看起来不错, 但是rc3仍然导致系统死机, 以及大量使用ifdef, 以及缺省打开CONFIG_NO_BOOTMEM, 导致了社区的怨气.

正常情况下, 新功能缺省情况下是不使能的. 新kernel应该尽最大可能和之前的kernel保持一致. 而CONFIG_NO_BOOTMEM缺省打开导致了很大的改变和问题.

Yinghai在2.6.35基础上又提交了一组patch, 使用logical memory block分配器替代early_res代码, 这组patch看起来比删除bootmem引入了更大的风险

--https://lwn.NET/Articles/382559/


在Yinghai删除bootmem patch的review过程中, 一些reviewers质疑为什么x86不使用logical memory block(LMB)分配器替换early-res的代码. 当X86使用类似brk()形式的early-res时 Microblaze, PowerPC, SuperH和SPARC架构已经使用LMB进行系统启动初期的内存分配, 所以LMB可以看做是一个generic的解决方案. 使用通用代码的好处是显而易见的: 更多的人review代码, 总体维护代价更带. 所以使用LMB明显更合理.

因此Yinghai在2.6.35上又提交了一组patch来简化启动分配器代码

Data structure

[cpp] view plaincopy
  1. struct memblock {     
  2. bool bottom_up;  /* is bottom up direction? */  
  3. phys_addr_t current_limit;
  4. struct memblock_type memory;  
  5. struct memblock_type reserved;  
  6. };

bootom_up 设置为true时, 允许内存分配使用bottom-up模式

current_limit memblock分配内存时的上限

memory 描述了当前内存区包含的内存区数目, 总大小, 以及每个内存region

reserved 描述了当前内存块已经分配的内存区数目, 总大小,以及每个内存region. 在reserved中描述的地址范围, 表示不可以再被memblock分配.

memory用来描述memblock全部内存region(不区分分配和未分配), reserved用来描述memblock中已经分配的内存region

[cpp] view plaincopy
  1. struct memblock_type {  
  2. unsigned long cnt;  /* number of regions */  
  3. unsigned long max;  /* size of the allocated array */  
  4. phys_addr_t total_size; /* size of all regions */  
  5. struct memblock_region *regions;  
  6. };

cnt         regions数目

max       最大regions数目

total_size    regions总尺寸

regions        regions array

[cpp] view plaincopy
  1. struct memblock_region {  
  2. phys_addr_t base;
  3. phys_addr_t size;
  4. unsigned long flags;  
  5. #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP  
  6. int nid;  
  7. #endif  
  8. };

base      region 基地址

size        region size

flags      region

memblock initialization

[cpp] view plaincopy
  1. static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;  
  2. static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;  
  3. struct memblock memblock __initdata_memblock = {  
  4. .memory.regions     = memblock_memory_init_regions,
  5. .memory.cnt     = 1,    /* empty dummy entry */  
  6. .memory.max     = INIT_MEMBLOCK_REGIONS,
  7. .reserved.regions   = memblock_reserved_init_regions,
  8. .reserved.cnt       = 1,    /* empty dummy entry */  
  9. .reserved.max       = INIT_MEMBLOCK_REGIONS,
  10. .bottom_up      = false,  
  11. .current_limit      = MEMBLOCK_ALLOC_ANYWHERE,
  12. };

.memory.regions 和reserved.regions固定数组, 最多支持128个regions

memory.mx和reserved.max的最大值也为128

current_limit 也被定义为最大可能物理地址


memblock API

在include/linux/memblock.h中定义了memblock的API

[cpp] view plaincopy
  1. int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)  
  2. {
  3. return memblock_reserve_region(base, size, MAX_NUMNODES, 0);  
  4. }

memblock_reserve API主要是为系统启动阶段为kernel(text, data and initrd), swapper_pg_dir, reserved-memory, memreserve等预留内存.

[cpp] view plaincopy
  1. int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)  
  2. {
  3. return __memblock_remove(&memblock.memory, base, size);  
  4. }

系统中有两处会调用memblock_remove:

1. early_init_dt_reserve_memory_arch中, 如果不希望这段内存被映射, 那么就调用memblock_remove, 把这段内存从memblock.memory中移除

2. arm_memblock_steal中, 调用memblock_remove从memblock.memory中偷一段内存空间, memblock.memory的regions中将不再包含这段内存空间.


[cpp] view plaincopy
  1. int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size)  
  2. {
  3. return memblock_add_region(&memblock.memory, base, size,  
  4. MAX_NUMNODES, 0);
  5. }

在memblock的memory type中增加一个region

base   是新增region的基地址

size    是新增region的尺寸

对于arm, 仅一处会调用memblock_add: arm_memblock_init 中根据meminfo向memblock.memory中增加region


memory和reserved region

memblock有两个memblock_type成员: memory和reserved

memblock.memory 描述memblock所有内存区(已分配的+未分配的)

memblock.reserved 描述已经分配的内存区, 所有分配和释放操作都是通过修改reserved来实现的. 分配操作在memblock.reserved上增加region, 释放操作则memblock.reserved上释放region.

memblock_reserved

[cpp] view plaincopy
  1. int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)  
  2. {
  3. return memblock_reserve_region(base, size, MAX_NUMNODES, 0);  
  4. }
  5. static int __init_memblock memblock_reserve_region(phys_addr_t base,  
  6. phys_addr_t size,
  7. int nid,  
  8. unsigned long flags)  
  9. {
  10. struct memblock_type *_rgn = &memblock.reserved;  
  11. return memblock_add_region(_rgn, base, size, nid, flags);  
  12. }

memblock_reserve -> memblock_reserve_region -> memblock_add_region

调用memblock_add_region时第一个参数为 memblock.reserved, 也就是说在memblock.reserved增加一个region

memblock_add_region流程如下:

1. 如果type->regions[0].size==0, 表示regions数组为空, 添加region[0], 设置region[0]相关成员,即可返回. 此时该memblock_type有一个region了

2. 计算要插入的region数目, [base, base + size]可能会跨越多个已存在的region, 因此数目可能不为1.

3. 由于要插入新region, 所以需要先扩展regions array.

4. 插入这些regions

5. 执行region merge操作

我们可以看到memblock_reserve()操作压根就没考虑memblock.memory, 因为memblock_reserve()只是告诉memblock, 这部分内存被保留了, 不要再参与memblock分配操作

memblock_alloc

[cpp] view plaincopy
  1. phys_addr_t __init memblock_alloc(phys_addr_t size, phys_addr_t align)
  2. {
  3. return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);  
  4. }
  5. phys_addr_t __init memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid)  
  6. {
  7. phys_addr_t res = memblock_alloc_nid(size, align, nid);
  8. if (res)  
  9. return res;  
  10. return memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ACCESSIBLE);  
  11. }

memblock_alloc->memblock_alloc_base->memblock_alloc_base_nid

[cpp] view plaincopy
  1. static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,  
  2. phys_addr_t align, phys_addr_t max_addr,
  3. int nid)  
  4. {
  5. phys_addr_t found;
  6. if (!align)  
  7. align = SMP_CACHE_BYTES;
  8. found = memblock_find_in_range_node(size, align, 0, max_addr, nid);
  9. if (found && !memblock_reserve(found, size))  
  10. return found;  
  11. return 0;  
  12. }

1. memblock_find_in_range_node查找符合条件的物理地址, 查找过程会涉及到查看memblock.reserve

2. 如果找到了这个物理地址, 调用memblock_reserve进行真正的分配(就是在memblock.reserve中添加region)

memblock_free

释放参数指定的内存区间

[cpp] view plaincopy
  1. int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)  
  2. {
  3. memblock_dbg("   memblock_free: [%#016llx-%#016llx] %pF\n",  
  4. (unsigned long long)base,  
  5. (unsigned long long)base + size - 1,  
  6. (void *)_RET_IP_);  
  7. return __memblock_remove(&memblock.reserved, base, size);  
  8. }

逻辑很简单, 从memblock.reserved中删除[base, base+size]指定范围的region. 这样下次调用memblock_alloc时再检查reserved type时, 这段区域可以再次使用了

【作者】张昺华
【出处】http://www.cnblogs.com/sky-heaven/
【博客园】 http://www.cnblogs.com/sky-heaven/
【新浪博客】 http://blog.sina.com.cn/u/2049150530
【知乎】 http://www.zhihu.com/people/zhang-bing-hua
【我的作品---旋转倒立摆】 http://v.youku.com/v_show/id_XODM5NDAzNjQw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【我的作品---自平衡自动循迹车】 http://v.youku.com/v_show/id_XODM5MzYyNTIw.html?spm=a2hzp.8253869.0.0&from=y1.7-2
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

相关文章:

with admin option /with grant option

1. with admin option是用在系统权限上的,with grant option是用在对象权限上的。 SQL> grant create synonym to scott with grant option;grant create synonym to scott with grant option *第 1 行出现错误:ORA-01939: 只…

第四层到第七层的高层交换技术及其应用

1 前言Internet的特点就是不断变化发展,目前网络上的信息量和业务量都呈现爆炸性的增长趋势。不断增长的负荷和新需求的出现,使得用单台服务器处理应用服务的结构已成为过去,取而代之的是以单一虚拟IP地址(VIP)来代表整个服务器集群&#x…

赠书 | 315之后,无人旁观时我们是谁

315的曝光,让人脸信息被随意采集、简历被低价出卖等话题受到公众热议。然而,不知道有多少人,直到这一场晚会才知道,原来自己始终是被悄悄“出卖”的人。智联招聘声称拥有1.8亿用户,视用户信息安全与隐私保护为自己“生…

bugzilla部署

Centos6.8部署bugzilla apache mysql1.apache可以使用系统自带的apache服务2.安装mysql:yum –y installmysql mysql-server //使用yum安装vi /etc/my.cnf //编辑mysql配置文件default-character-set utf8 //在mysql_safe段添加字符集支持service mysq…

ASP.NET 2.0 AJAX中Webservice调用方法示例

ASP.NET 2.0 AJAX中能够在客户端js中很方便地调用服务器Webservice,以下为一些调用的示例。笔者安装的ASP.NET 2.0 AJAX 版本为AJAX November CTP。 三个示例分别为:1 带参数的WS方法2 不带参数的WS方法3 参数类型为DataTable的WS方法一、WebMethod注意…

Python 玩出花儿,把罗小黑养在自己桌面

作者 | 李秋键责编 | 寇雪芹出品 | AI科技大本营(ID:rgznai100)引言:了解过我们之前文章的都知道我们曾经做过一个智能桌宠项目。但是很显然那个程序过于卡段。故这一次我们将重新制作个智能桌宠项目,不同于之前的项目在于&#x…

Google推荐的15条HTML 5代码军规----来看看你知道几个,我一个都不知道。。。

Google规范的原文链接大家可以访问:http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml  1.协议头:  建议在指向图片或其他媒体文件、样式表和脚本的URL地址中省略http:https:协议部分,除非已知相应文件不能…

OTS parsing error: invalid version tag woff和ttf文件被Filter拦截

从服务器下载的字体文件放在本地,执行无法展示iconfont,浏览器控制台报出 Failed to decode downloaded font: http://127.0.0.1:8080/mhr/group-assets/iconfont/iconfont.ttf?t1500884389272login_group.html:1 OTS parsing error: invalid version t…

asp.net 的性能计数器

ASP.NET 支持两组性能计数器:系统和应用程序。前者在 ASP.NET 性能计数器对象中的 PerfMon 中公开;后者在 ASP.NET Applications 性能对象中公开。ASP.NET 性能对象中的 State Server Sessions 计数器(仅适用于在其中运行状态服务器的服务器计…

为什么那么多程序员不敢学Python?

Python入门从哪开始?90%以上的书上都是这样讲的:先介绍 Python 的基本语法规则、list、dict、tuple 等数据结构,然后再介绍字符串处理和正则表达式,介绍文件等IO操作.... 就这样一点一点往下说。然而这种按部就班的学习方法&#…

5 配置邮箱服务器

配置邮箱服务器 一邮箱服务器角色 当Exchange邮件服务器使用一段时间后可能面临以下几个问题:邮箱服务器的磁盘空间出现不足、如何将数据库文件移到新的硬盘上、如何共享一些文件给指定的人;为了解决这些问题,我们就要了解邮箱服务器中的邮件…

mongodb 连接和备份

2019独角兽企业重金招聘Python工程师标准>>> 1.查询某一列的值: db.collection_name.find({},{key:1,key1:0}) 第一个 {} 放 where 条件,为空表示返回集合中所有文档 第二个 {} 指定那些列显示和不显示 (0表示不显示 1表示显示[非0都是显示])…

HTTP和SOAP完全就是两个不同的协议

HTTP只负责把数据传送过去,不会管这个数据是XML、HTML、图片、文本文件或者别的什么。而SOAP协议则定义了怎么把一个对象变成XML文本,在远程如何调用等,怎么能够混为一谈。 这样说两种协议: HTTP就是邮局的协议,他…

对网络骚扰和霸凌说不!神经网络可以做得更好

导语:无论在论坛、评论区还是游戏聊天界面,网络骚扰和网络霸凌都是一件让人烦恼的事。怎样避免这些烦人的问题?也许本文介绍的神经网络模型,可以对于使用AI技术手段解决这些问题有所启示。译者 | Rachel头图 | 下载于东方 IC出品 …

主机入侵防御系统(HIPS)分析

主机入侵防御系统(Host Intrusion Prevent System,HIPS)是近几年出现并迅速发展的新兴产物,与传统意义的防火墙和杀毒软件不同,它并不具备特征码扫描和主动杀毒等功能,所以想用它来替换传统杀毒软件然后安枕…

Centos 7 让docker飞一会儿

为什么80%的码农都做不了架构师?>>> 安装shadowsocks yum install -y epel-release python-pip pip install shadowsocks vim /etc/shadowsocks.json {"server": "your.vpn.com","server_port": 8388,"password&quo…

.net应用程序如何批上XP的外衣?

.net framework 所提供的开发控件也太少了,也太难看了,自已画又费时费力也不见得会得出个什么好的效果。如果能够上我们的程序运行在XP环境中能自动应用XP的主题样式那就省时多了,让MICROSOFT给我们去画控件!以下是我所所试验过的解决办法: …

AppCan 学习

2019独角兽企业重金招聘Python工程师标准>>> AppCan 学习 AppCan是以web前端开发方式来开发移动app的解决方案。下面是一些记录: 1.注意 uexWindow.open和uexWindow.openPopover的不同,后者是pop,pop里不能在打开window了。 2.…

在 5G 速度上,iPhone 12 只是个弟弟

作者 | 郑丽媛头图 | 下载自东方 IC出品 | CSDN(ID:CSDNnews)如果不考虑价格因素,让你选择一部手机,你是选 iPhone 还是安卓手机?目前,移动操作系统市场被 iOS 和安卓系统瓜分,体现在…

hadoop install start-dfs.sh 失败

linux:ubuntu 16.04 LTS hadoop version: 2.7.3 JDK: java-9-open-jdk issue: start-dfs.sh start-dfs.sh:command not found 在hadoop sbin目录下可以找到这个文件。但是run不起来。 解决方法: 1. 打开 $HOME/.bashrc 加入下面一行。 PATH$PATH:/usr/l…

用.net中的socket实现文件传输

socket是网络套接字,使用它我们可以很方便的实现网络的数据传输。在.net中提供了socket类来帮助开 发者调用socket的使用,从而避免了调用socket的动态库来实现socket的麻烦。下面我们就来看一个简单的例子,从这个简单的例子来看看.net中的so…

ARP协议学习

Dolphin,ChinaBJ,20131122本文档是检验自己学习TCP/IP协议卷1:协议中关于ARP协议的学习情况。本文档包含以下四部分:1、简述ARP协议;2、ARP的分组格式;3、ARP Spoofing 实验 4、应用及防御方法。1.简述ARP协…

数学,对人工智能开发者意味着什么

21世纪以来,全球化的加速和互联网的蓬勃发展,带来全球范围内电子数据的爆炸性增长,人类迈入了大数据时代。与此同时,计算机芯片的计算能力也持续高速增长。在数据和计算能力指数式增长的支持下,人工智能算法在应用中取…

检查网站是否可以正常访问

# -*- coding: utf-8 -*-import urllib.request import time opener urllib.request.build_opener() opener.addheaders [(User-agent, Mozilla/49.0.2)] #文件格式http://www.baidu.comfile open(E:/auto/url.txt) lines file.readlines() aa[] for line in lines: templ…

使用.NET自带的类实现DataGrid报表的打印。

using System;using System.Windows.Forms;using System.Drawing;using System.Drawing.Printing;using System.Data;using System.Collections;using DataLibrary; namespace ControlLibrary{ /// <summary> /// DataGrid打印 /// </summary> public class DataG…

各种 AI 数据增强方法,都在这儿了

来源 | 算法进阶责编 | 寇雪芹头图 | 下载于视觉中国数据、算法、算力是人工智能发展的三要素。数据决定了Ai模型学习的上限&#xff0c;数据规模越大、质量越高&#xff0c;模型就能够拥有更好的泛化能力。然而在实际工程中&#xff0c;经常有数据量太少(相对模型而言)、样本不…

ORACLE11g 前期安装环境配置

Linux系统可以拿来直接用的脚本哦#!/bin/bashservice iptables stop &> /dev/nulliptables -F service iptables save &> /dev/nullsed -i s/enforcing/disabled/ /etc/selinux/configsetenforce 0sed /tmpfs/d /etc/fstab &> /dev/nullecho tmpfs …

linux mysql 卸载,安装,測试全过程

Mysql卸载yum remove mysql mysql-server mysql-libs compat-mysql51rm -rf /var/lib/mysqlrm /etc/my.cnf查看是否还有mysql软件&#xff1a;rpm -qa|grep mysql有的话继续删除Mysql安装1>若本地没有安装包 能够考虑使用yum命令进行下载# yum -y install mysql-server# yum…

C#中获取程序当前路径的集中方法

string str1 Process.GetCurrentProcess().MainModule.FileName;//可获得当前执行的exe的文件名。 string str2Environment.CurrentDirectory;//获取和设置当前目录&#xff08;即该进程从中启动的目录&#xff09;的完全限定路径。//备注 按照定义&#xff0c;如果该进程在本…

如何开启远程(win7win8)

如何开启远程连接点击我的电脑-属性-高级系统设置-远程-选中“允许远程连接到此计算机”-应用-确定。在局域网内&#xff0c;拥有固定IP的话&#xff0c;就很容易远程处理事情了。若经过此步骤还不能远程的话&#xff0c;则需要查看系统是否开启了远程服务。“我的电脑”--管理…