内核采用 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. limit_choices_to

    # 多对多 老师 teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo', related_name="ab ...

  2. linux--->linux下composer 安装

    composer 安装 进入var/src目录中 下载composer安装包 curl -sS https://getcomposer.org/installer | php 设置全局访问 sudo ...

  3. Intellij IDEA使用(一)项目模板类型

    概述 IDEA默认打开后,会出现欢迎页面,可以选择打开Project的方式. 对于新建的Project,一般会选择[Create New Project],对于界面中,众多的Project类型,有时候 ...

  4. SQLException:The server time zone

    报错信息如下: java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represen ...

  5. learn more ,study less(二):整体性学习技术(上)

    前言:在学习整体性学习概念时,一个很好的方法是把它比喻成下棋,首先你要了解下棋的 基本规则和基本目标,本书第一部分可以看做是介绍关于整体性学习的一整套规则和目标. 一旦你理解了下棋的基本规则,你就要开 ...

  6. js之split()和join()的用法

    说明 这几天写了一个简单的vue项目,需要截取字符串,一时间想到了正则表达式,还折腾了还一会儿,最后上网查了一下,使用split()再简单不过了,也顺便回忆一下join().可见我有多菜,哈哈,学了这 ...

  7. 脚本实现统计osd内的pg数量

    脚本代码如下: ceph pg dump | awk ' /pg_stat/ { col=; while($col!=“up”) {col++}; col++ } /[-9a-f]+.[-9a-f]+ ...

  8. eclipse运行python 安装pydev 版本匹配问题

    Eclipse 4.5, Java 8: PyDev 5.2.0 PyDev 5.2.0 版本路径:https://dl.bintray.com/fabioz/pydev/5.2.0 1.安装时注意: ...

  9. Java中的8种基本数据类型

    JAVA中的8种基本数据类型:byte short int long float double char boolean 特别说明: 1)char类型占2个字节,可以表示汉字.汉字和英文字符都占2个字 ...

  10. re模块 findall()详解

    1. findall() 函数的2种表示形式 import re kk = re.compile(r'\d+') kk.findall('one1two2three3four4') #[1,2,3,4 ...