内核采用 struct page 来表示一个物理页,在其中记载了诸多物理页的属性,比如 物理页被几个线程使用(如若没有则表示该页可以释放),页对应的虚拟地址。

  首先需要知道的是,分配物理页可以分为两个步骤 :

    1) 寻找内核中空闲 处于3-4G 4K对齐的虚拟地址。

        i)虚拟页是否空闲 由页表项的属性决定,里面会有标志位记录。

        ii)虚拟页需要4K对齐是强制性的,因为页目录项的低12 bit是用来记录页目录属性的,高20 bit才是记录页目录项的物理地址。

    2) 寻找内核中空闲的物理页。

    3) 通过改变页表项来修改映射关系,如何修改的请看 我的另一篇博客 : https://www.cnblogs.com/vizdl/p/11925205.html

 // 物理页表示
struct page {
unsigned 1ong flags ;
atomic_t _count ;
atomic_t mapcount;
unsigned 1ong private;
struct address_space * mapping;
pgoff_t index;
struct list_ head lru;
void *virtual;
}; 

  由物理地址进行分区 : 在系列文章2中也讲了分区的一些缘由,详情可看系列博客2中内核空间分区部分 https://www.cnblogs.com/vizdl/p/12233623.html

  内核空间一般被分为三个区 : ZONE_DMA, ZONE_NORMAL, ZONE_HIGHMEM,直接提供的接口可以建议内核从特定区域申请物理页。

struct zone
{
unsigned long
watermark[NR_ WMARK];
unsigned 1ong lowmem_ reserve[MAX_ NR_ ZONES];
struct per_cpu_pageset pageset[NR_CPUS];
spinlock_t lock;
struct free_ area
free_area[MAX_ ORDER] spinlock_t
lru_1ock;
struct zone_1ru
{
struct list_head list;
unsigned 1ong nr_saved_scan;
} lru[NR_ LRU_ LISTS];
struct zone_reclaim_ stat reclaim_ stat;
unsigned long pages_scanned;
unsigned long flags;
atomic_1ong_t vm_stat[NR_ _VM_ ZONE STAT_ ITEMS];
int prev_priority;
unsigned int inactive_ratio;
wait_queue_head_t *wait_ table;
unsigned 1ong wait_ table_ hash_ nr_ entries;
unsigned 1ong wait_ table_ bits;
struct pglist_ data *zone_ pgdat;
unsigned long zone_ start_ pfn;
unsigned long spanned_ pages;
unsigned 1ong present_ pages;
const char *name;
};

  对物理页操作接口: 物理页采用buddy算法来进行分配,单位最小为1页。只能申请2^order页,这也是buddy算法的特性。

  特别说明 :

  1) gfp_t gfp_mask,这个参数就是用来建议内核在具体哪个区域得到物理页。

  2) 如若已经无可用物理页了,就会采用一系列 页面置换算法, 将物理页上的内容保存到磁盘中的swap sapce(交换空间)中去。

// 分配 2^order个连续的物理页(使用buddy);
struct page *al1oc_ pages(gfp_t gfp_mask, unsigned int order);
// 利用page中的 virtual属性 得到对应的虚拟地址。
void *page_address(struct page *page);
// 分配 2^order个连续的物理页,且直接返回逻辑地址
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);
// 分配一页物理内存
struct page *alloc_page(gfp_t pfp_mask);
// 分配一页物理内存 并返回逻辑地址
struct page *__get_free_page(gfp_t pfp_mask);
// 获取填充为0的页
unsigned long get_zeroed_page(unsigned int gfp_mask);

  物理页的释放函数 :

// 释放物理地址
void __free_pages(struct page *page, uns igned int order);
void free_pages(unsigned long addr, unsigned int order);
void free_page(unsigned 1ong addr);

  

  对于小块内存分配,内核也提供了Slab分配器来进行分配,这个分配器可以提供一个缓冲,不会将申请的物理解除绑定虚拟地址,理由是一些小块的内存(特别是结构体)会在内核中频繁地申请与释放。

  Slab层的一些接口 :

// 字节为单位的内存分配(slab层)
// kmalloc()在<linux/slab.h>中声明:
// 分配物理地址连续的地址, 出错返回NULL
void *kmalloc(size_t size, gfp_t flags);
// 物理不一定连续,虚拟连续。
void *vmalloc(unsigned long size);
// 释放
void kfree(const void *ptr);
void vfree(const void *addr);

  slab层的好处 :

    1) 避免了频繁地寻找空闲虚拟页和空闲物理页,提高效率。

    2) 避免了因频繁修改物理页与虚拟页映射关系而导致的物理页无法有大块平坦(连续)物理空间。

  slab本质其实就是一个内存池。 而内存池之后我可能会总结malloc的内存分配算法,那个算法完全可以用于slab。不过一个是堆内存池,一个是内核内存池。

  slab与Buddy的关系:

  

  由上述 : 目前对于内核空间的内存分配已经有一个简单的策略认识了, 即 小块内存 用slab分配器分配,大块内存(最小单位为页)用 Buddy系统 直接分配。而slab层内存池的内存也是Buddy分配出来的。只不过Slab在此做了一个缓冲罢了。

Linux内存管理解析(三) : 内核对内核空间的内存管理的更多相关文章

  1. linux(centOS7)的基本操作(三) 用户、组、权限管理

    用户和组 1.用户.组.家目录的概念 linux系统支持多用户,除了管理员,其他用户一般不应该使用root,而是应该向管理员申请一个账号.组类似于角色,系统可以通过组对有共性的用户进行统一管理.每个用 ...

  2. Android内存优化(三)避免可控的内存泄漏

    相关文章 Android性能优化系列 Java虚拟机系列 前言 内存泄漏向来都是内存优化的重点,它如同幽灵一般存于我们的应用当中,有时它不会现身,但一旦现身就会让你头疼不已.因此,如何避免.发现和解决 ...

  3. Linux内核入门到放弃-内存管理-《深入Linux内核架构》笔记

    概述 内存管理的实现涵盖了许多领域: 内存中的物理内存页管理 分配大块内存的伙伴系统 分配较小内存块的slab.slub和slob分配器 分配非连续内存块的vmalloc机制 进程的地址空间 在IA- ...

  4. (转)Linux环境进程间通信系列(五):共享内存

    原文地址:http://www.cppblog.com/mydriverc/articles/29741.html 共享内存可以说是最有用的进程间通信方式,也是最快的 IPC 形式.两个不同进程 A ...

  5. Java中OutOfMemoryError(内存溢出)的三种情况及解决办法

    转载自:http://blog.sina.com.cn/s/blog_701c951f0100n1sp.html 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题, ...

  6. jvm内存溢出的三种情况以及解决办法

    1       前言相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深 ...

  7. Android内存优化(三)详解内存分析工具MAT

    前言 在这个系列的前四篇文章中,我分别介绍了DVM.ART.内存泄漏和内存检测工具的相关知识点,这一篇我们通过一个小例子,来学习如何使用内存分析工具MAT. 1.概述 在进行内存分析时,我们可以使用M ...

  8. Linux内核设计笔记12——内存管理

    内存管理学习笔记 页 页是内核管理内存的基本单位,内存管理单元(MMU,管理内存并把虚拟地址转化为物理地址的硬件)通常以页为单位进行处理,从虚拟内存的角度看,页就是最小单位. struct page{ ...

  9. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

随机推荐

  1. Linux下利用Ant调用Jmeter脚本生成HTML测试报告

    今天我们学习如何利用Ant调用Jmeter脚本,并将生成的 jtl 文件转换为 HTML 格式的测试报告. 准备工作 需要在Linux上提前安装好 JDK. Jmeter 和 Ant. 1,JDK(可 ...

  2. Scala 学习(4)之「类——基本概念2」

    目录 内部类 extends override和super override field isInstanceOf和asInstanceOf getClass和classOf 内部类 import s ...

  3. cocos2dx,Layer锚点与scale缩放

    最近写代码需要用到缩放,而且是Layer的,但是发现怎么设置位置都是错误,于是决定研究下. 首先,基础代码,代码上不错特殊处理,没有锚点设置和缩放 class TestLayer : public L ...

  4. python常用内置模块-random模块

    random模块:用于生成随机数 '''关于数据类型序列相关,参照https://www.cnblogs.com/yyds/p/6123692.html''' random() 随机获取0 到1 之间 ...

  5. CSS基础应用总结

    目录 CSS 样式笔记 文字水平居中和垂直居中 如何设置a标签不带下划线 控件右对齐 div上下居中 控件左右居中 控件展示在同一行 设置文字超出部分...显示 CSS 样式笔记 文字水平居中和垂直居 ...

  6. SEO 搜索 形成一个关联

  7. Python学习,第三课 - 数据类型

    前言. 本次针对Python中的数据类型,做详细的总结 1.数字 2 是一个整数的例子. 长整数 不过是大一些的整数. 3.23和52.3E-4是浮点数的例子.E标记表示10的幂.在这里,52.3E- ...

  8. 龙芯 fedora28 安装指南

    版权声明:原创文章,未经博主允许不得转载 关于硬件 龙芯3号的板子安装系统都差不多,我分别在 Lemote A1310 和 Lemote A1901 上都尝试过. 本文主要依据 Lemote A190 ...

  9. http1.0、http1.x、http 2和https梳理

    http1.0.http1.x.http 2和https梳理 Http1.x 线程阻塞,在同一时间,同一域名的请求有一定数量限制,超过限制数目的请求会被阻塞 http1.0 缺陷:浏览器与服务器只保持 ...

  10. Shell之信号捕获

    前言 当我们在运行某一段代码的时候,希望有类似事物一样的操作,要么成功,要么失败:一般的shell脚本都是自上而下,从左之后运行,碰到异常信号就会出错,从而终止脚本的运行,这个时候脚本可能运行到某一处 ...