内核采用 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. ORM基础3 在python脚本里调用Django环境

    1.查询 1.# all获取所有的object,结果QuerySet,列表 print('all'.center(80, '=')) ret = models.Person.objects.all() ...

  2. 5.Switch多选择结构

    Switch语句: 多选择结构还有一个实现方式就是 switch case 语句 switch case 语句判断一个变量与一系列值中的某个值是否相等,每个值称为一个分支. switch语句中的变量类 ...

  3. http请求头中的content-type属性

    在HTTP请求中,我们每天都在使用Content-Type来指定不同格式的请求信息,但是却很少有人去全面了解Content-Type中允许的值有多少,因此这里来了解一下Content-Type的可用值 ...

  4. ninject 的 实现 的 理解

    mvc 用ninject 好像 有 的. 加上 ClassDiagram  .ClassDiagram1.rar Represents a site on a type where a value c ...

  5. HCNA 2017年01月26日

    [Huawei]ping 127.0.0.1 PING 127.0.0.1: 56 data bytes, press CTRL_C to break Reply from 127.0.0.1: by ...

  6. 《阿k学Python》一Python入门(一)

    前言 各位看博客的园友们,大家好,我就是那个风流倜傥的KK,还记得我那篇2019年的年中总结博客吗?我想有许多看博客的园友是没有读过我那篇文章的,KK很生气,后果很严重(开个玩笑了,怎么可能).给大家 ...

  7. Linux 常用工具openssh之ssh-add

    前言 ssh-add命令是把专用密钥添加到ssh-agent的高速缓存中,从而提高ssh的认证速度 语法 ssh-add [-cDdLlXx] [-t life] [file ...] 选项 -D:删 ...

  8. Shell重定向与exec

    前言 首先我们需要知道exec是什么,exec是linux下面一个创建进程的方法,详情请参考:https://www.cnblogs.com/guge-94/p/11016176.html 重定向 概 ...

  9. ActiveMQ 快速入门教程系列 第二章 发布-订阅者模式实现

    第二章我们会介绍怎样实现一个发布者对多个订阅者的消息传递 Topic和queue的最大区别在于topic是以广播的形式,通知所有在线监听的客户端有新的消息,没有监听的客户端将收不到消息:而queue则 ...

  10. Python 中的三元运算(软件测试中运用)

    前言 在java中,有类似于 (condition) ? a :b 这样的语法,表示如果condition 为真,返回a,反之返回b.我们称之为三元运算. 那Python中,有没有这样的语法呢,非常遗 ...